![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
События динамически создаваемых объектов [D6]
msguns © (2005-07-19 15:43:00)Извиняюсь за ламерство, но таких вещей просто не делал, а у Тексейры как-то вскользь об этом ;(
Библиотечный юнит создает форму и "кладет" на нее необходимые объекты. А вот как назначить обработку событий этих объектов - ума не приложу. В Dialog.pas это делается через промежуточный класс TMessageForm, можно ли обойтись без него ?
Код:
procedure DBServ_SearchRecordByUserDialog(Grid: TDBGrid);
// Создание окна поискового диалога
Const
MinHeight: integer = 200;
MinWidth: integer = 360;
var
i: integer;
SearchForm: TForm;
SamplePanel: TPanel;
LablPromptCol: TLabel;
ColumnList: TComboBox;
begin
// Создать форму
SearchForm := TForm.Create(Grid.Owner);
with SearchForm do
begin
BorderIcons := [biSystemMenu];
BorderStyle := bsSingle;
Position := poOwnerFormCenter;
Height := MinHeight;
Width := MinWidth;
Caption := 'Поиск записей по значению колонки';
end;
// Создать панель пользователя
SamplePanel := TPanel.Create(SearchForm);
with SamplePanel do
begin
Parent := SearchForm;
Align := alTop;
BevelOuter := bvLowered;
Height := 40;
end;
// Создать надпись
LablPromptCol := TLabel.Create(SearchForm);
with LablPromptCol do
begin
Caption := 'Поиск по колонке ';
Left := 4;
Top := 6;
Parent := SamplePanel;
end;
// Создать комбобокс для списка колонок
ColumnList := TCombobox.Create(SearchForm);
with ColumnList do
begin
Top := 2;
Parent := SamplePanel;
Left := LablPromptCol.Left+LablPromptCol.Width+4;
Width := MinWidth-Left-10;
Sorted := false;
// Заполнить список названиями колонок
for i := 0 to Grid.Columns.Count-1 do
if Grid.Columns[i].Field.FieldKind=fkData then
begin
Items.Add(Grid.Columns[i].Title.Caption);
if Grid.Columns[i].Field=Grid.SelectedField then
ItemIndex := i; // Текущее поле
end;
OnChange := ????
end;
SearchForm.ShowModal;
end;
Огромное спасибо всем откликнувшимся
evvcom (2005-07-20 10:17:00) [21]
> как бы отдельная и независимая ни от других функций (процедур),
> ни от самого модуля в целом.
Это что, обязательное условие? Нельзя себя так ограничивать. Что мешает procedure OnChangeColumn вынести чуть выше procedure DBServ_SearchRecordByUserDialog? Даже в interface ее не нужно прописывать. И будут они в паре самодостаточны.
> Чтобы "передать" фунции-"обработчику" ссылку на грид, необходимо
> воспользоваться глобальной переменной
Зачем? В Sender у тебя будет ComboBox, а в Self (см. [5], что похоже ты игнорировал) можешь положить свой Grid.
jack128 (2005-07-20 10:13:00) [22]Если чесно ничего не понял. Что конкретно мешает сделать процедуру глобальной?? И причем здесь глобальные переменные?
msguns © (20.07.05 9:36) [15]
как бы отдельная и независимая ни от других функций (процедур),
Гм.. Это как ?? Не, ну если у тебя в функциях используются только ОПЕРАТОРЫ... А вот например твоя функция DBServ_SearchRecordByUserDialog точно зависит от других функций и методов..
msguns (2005-07-20 09:36:00) [23]>Юрий Зотов © (20.07.05 04:43) [14]
>Мое ИМХО совпадает с ИМХО Жени - для начала надо попробовать вынести внутреннюю процедуру наружу. Дальше будет видно. Скорее всего, ошибка просто исчезнет.
Плохо. Во-первых, все это у меня в библиотечном модуле, реализующем набор сервисных функций для определенного класса датасетов, написанном с целью унификации кодинга и каждая функция как бы отдельная и независимая ни от других функций (процедур), ни от самого модуля в целом. Т.е. как бы самодостаточа. Чтобы "передать" фунции-"обработчику" ссылку на грид, необходимо воспользоваться глобальной переменной, чего мне делать не хочется (следуя стилю Тексейры).
Видимо, без объявления класса вроде TMessageDialog из модуля Dialogs для инкапсуляции всего, что нужно для этой формы, не обойтись.
Или я неправ ?
Юрий Зотов (2005-07-20 04:43:00) [24]> AlexWlad © (19.07.05 19:40) [10]
> Ю Метод д.б. в секции PRIVATE.
Извините, но даже спорить не стану.
> msguns © (19.07.05 19:27) [9]
Мое ИМХО совпадает с ИМХО Жени - для начала надо попробовать вынести внутреннюю процедуру наружу. Дальше будет видно. Скорее всего, ошибка просто исчезнет.
> ЮЮ © (20.07.05 03:28) [13]
Grid объявлен в параметрах. Это тоже объявление.
ЮЮ (2005-07-20 03:28:00) [25]я тоже не вижу никакого объявления Grid, а только его использование :)
jack128 (2005-07-19 20:50:00) [26]И вообще, что вы привезались к этим хакам с приведением к Tmethod
type
TEventHandlers = class
class procedure ChangeColumnHandler(Sender: TObject);
end;
class procedure TEventHandlers.ChangeColumnHandler(Sender: TObject);
begin
ShowMessage('Test');
end;
...
ColumnList.OnChange := TEventHandlers.ChangeColumnHandler;
...
jack128 (2005-07-19 20:47:00) [27]msguns © (19.07.05 19:27) [9]
Сравни
msguns © (19.07.05 19:27) [9]
procedure OnChangeColumn(Sender: TObject);
и
Юрий Зотов © (19.07.05 16:59) [7]
procedure ColumnListChange(Self: TComboBox; Sender: TObject);
ps Возможно из-за того чтоо функция локальная возникнут проблемы, лудше сделай её глобальной..
AlexWlad (2005-07-19 19:40:00) [28]Юрий Зотов © (19.07.05 16:59) [7]
>Обработчиком события OnChange может быть метод любого класса, имеющий единственный параметр Sender: TObject.
Метод д.б. в секции PRIVATE.
msguns (2005-07-19 19:27:00) [29]
procedure DBServ_SearchRecordByUserDialog(Grid: TDBGrid);
var
...
MColChange: TMethod;
procedure OnChangeColumn(Sender: TObject);
var
i: integer;
begin
// Определить имя поля датасета по титулу выбранной колонки
for i := 0 to Grid.Columns.Count-1 do
if (Grid.Columns[i].Field.FieldKind=fkData) and
(Grid.Columns[i].Title.Caption=ColumnList.Items[ColumnList.Itemindex]) then
begin
// Сделать выбранную колонку текущей в гриде
Grid.SelectedIndex := i;
break;
end;
Grid.Invalidate;
end;
begin
MColChange.Code := @OnChangeColumn;
..
ColumnList := TCombobox.Create(SearchForm);
with ColumnList do
begin
Top := 2;
Parent := SamplePanel;
Left := LablPromptCol.Left+LablPromptCol.Width+4;
Width := MinWidth-Left-10;
Sorted := false;
// Заполнить список названиями колонок
for i := 0 to Grid.Columns.Count-1 do
if Grid.Columns[i].Field.FieldKind=fkData then
begin
Items.Add(Grid.Columns[i].Title.Caption);
if Grid.Columns[i].Field=Grid.SelectedField then
ItemIndex := i; // Текущее поле
end;
OnChange := TNotifyEvent(MColChange);
end;
end;
При изменении в комбобоксе AV в выделенном коде (не видит Grid)
Где грабли ?
msguns (2005-07-19 18:25:00) [30]>Юрий Зотов © (19.07.05 16:59) [7]
Спасибо. То, что нужно ;)
Юрий Зотов (2005-07-19 16:59:00) [31]> msguns © (19.07.05 16:17) [2]
Обработчиком события OnChange может быть метод любого класса, имеющий единственный параметр Sender: TObject.
Любого класса. Хоть формы, хоть не формы, хоть главной, хоть не главной.
Поэтому, если у Вас есть любой собственный класс, то можно ввести такой метод в него. А если нет, то компилятор можно "обмануть" и использовать обычную процедуру:
procedure ColumnListChange(Self: TComboBox; Sender: TObject);
begin
ShowMessage(Self.ClasName)
end;
var
M: TMethod;
...
M.Code := @ColumnListChange;
M.Data := ColumnList;
ColumnList.OnChange := TNotifyEvent(M);
evvcom (2005-07-19 16:52:00) [32]
> А прописать ее в уните можно вставив описание до implementation
без разницы где, главное, чтобы она была видна в месте упоминания/присвоения.
evvcom (2005-07-19 16:51:00) [33]
procedure EmulateMethodOnChange(Self: Pointer; Sender: TComboBox);
begin
...
end;
var
l_pMyData: Pointer;
...
with TMethod(ColumnList.OnChange) do begin
Code := @EmulateMethodOnChange;
Data := l_pMyData;
end;
в качестве Self можешь передать любые дополнительные данные l_pMyData. Имена и типы в EmulateMethodOnChange можешь подставлять какие хочешь, главное, чтобы количество параметров соответствовало ColumnList.OnChange (вроде ты знаешь, что первым параметром, если не хакать, неявно Self передается). Но знай, что в качестве Sender туда в твоем случае ColumnList передастся.
ZlDoc (2005-07-19 16:50:00) [34]А что если на событие повесить процедуру не относящуюся ни к одному классу. Сам не проверял, но советую попробовать.
А прописать ее в уните можно вставив описание до implementation.
Stakan (2005-07-19 16:37:00) [35]Как мне кажется, можно завести в модуле спец. класс, методы которого будут обработчиками событий для контролов на форме. И указатели на методы этого класса присваивать событиям контролов.
msguns (2005-07-19 16:17:00) [36]Эту статью перечитал еще раз (место про события). Однако в приведенном примере есть форма, у которой определяется соответствующее событие:
Procedure TForm1.OnClickButton( Sender : TObject );
Var Value : String;
Begin
MessageDlg('Нажата кнопка '+TControl(Sender).Name ,mtInformation,[mbOk],0);
End;
А затем указатель на это событие класса-формы присваивается событию OnClick батона.
У меня же юнит. Формы в дизайне нет. Получается, что мне надо ее прописать в интерфейсе модуля ?
Если не трудно, покажите, как это делается
Юрий Зотов (2005-07-19 15:53:00) [37]http://www.delphikingdom.com/asp/viewitem.asp?catalogid=342
Снимет все вопросы по этой теме.