![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
||||
|
||||
|
Приветствую вас, форумчане !
Прошу помощи в вопросе работы с классами. Длительное время я писал код, не создавая свои классы, что в итоге выливалось в кучу лишней работы. И сейчас решил наконец попробовать, провёл первые простейшие эксперименты. Замысел такой: определить некие "мега-объекты" - в моём случае это дерево классификации, связанная с деревом таблица БД, и куча управляющих кнопок и прочих контролов. Для этих "мега-объектов" прописать логику работы, и затем создавать экземпляры класса "мега-объект", и связывать их с соответствующими контролами на форме, созданными в дизайн-тайме. Простейший эксперимент показал, что это работает. Однако далее я столкнулся с вопросом использования методов объектов, находящихся внутри класса. Для пробы в моём классе были определены дерево и кнопка Expand/Collapse: Код:
type
TMegaObject = class
public
uTree: TTreeView;
aExpandCollapseButton: TSpeedButton;
procedure aExpandCollapseButtonClick(Sender: TObject);
end;
.... (код обработчика aExpandCollapseButtonClick).Код:
procedure TForm1.FormCreate(Sender: TObject); begin mObj1:= TMegaObject.Create; mObj1.uTree := tree; mObj1.aExpandCollapseButton := SpeedButton3; mObj1.aExpandCollapseButton.OnClick := aTree.aExpandCollapseButtonClick; mObj2:= TMegaObject.Create; ...... end; Нажатия / отжатия кнопки Expand/Collapse отрабатывались правильно, для любого количества экземпляров данного пользовательского класса. Но вот возникла необходимость обрабатывать событие OnChange дерева uTree, объявленного в классе. Причём так, чтобы получать все параметры, которые объект TreeView передаёт в тело процедуры. Как это сделать – я не понял, и ответа в Инете нигде не нашёл. В рамках "метода тыка" я объявил в своём классе, в секции public, процедуру с теми же параметрами, что и у OnChange стандартного TreeView: Код:
procedure uTreeChange(Sender: TObject; Node: TTreeNode); Затем в конструкторе своего класса прописал: Код:
constructor TMegaObject.Create; begin inherited; uTree.OnChange := uTreeChange; end; Пробовал (понимая, что бредовое присвоение) в FormCreate написать: Код:
mObj1.uTree.OnChange := mObj1.uTreeChange; Тут уже компилятор не пропустил такую строку. А без связи процедур uTreeChange с uTree.OnChange ничего не будет происходить - объявленная процедура висит в воздухе, ни с чем не связанная. И объявить процедуру uTree.OnChange, чтобы написать для неё обработчик, тоже никак не получилось. Уже кучу вариантов перебрал, и Self.uTree.OnChange пытался как-то прилепить – ничего не получается. Нутром чую – тут должно быть просто, но как? Что удивительно – нигде в просмотренных мною инетовских статьях этот вопрос даже не поднимается. Понимаю, что мои потуги со стороны выглядят идиотизмом, но я действительно впервые пробую работать с собственными классами. Поэтому прошу подсказки по данному вопросу. |
|
#2
|
|||
|
|||
|
Тут у тебя проблема с пониманием цикла жизни объектов. Ну или с пониманием сути объектных ссылок.
Судя по твоему коду, ты пытаешься установить обработчик события еще до того, как присваиваешь аттрибуту своего объекта ссылку на реально существующий контрол. Вот так все работает: Объект (упрощеный, только для демонстрации): Код:
unit Unit2;
interface
uses
Vcl.ComCtrls, Vcl.Dialogs;
type
TMyObject = class
private
FTree : TTreeView;
procedure SetTree(const Value: TTreeView);
protected
procedure OnTreeViewChange(Sender : Tobject; Node : TTreeNode);
public
constructor Create;
property Tree : TTreeView read FTree write SetTree;
end;
implementation
{ TMyObject }
constructor TMyObject.Create;
begin
FTree := Nil;
end;
procedure TMyObject.OnTreeViewChange(Sender: Tobject; Node: TTreeNode);
begin
ShowMessage('On tree change.');
end;
procedure TMyObject.SetTree(const Value: TTreeView);
begin
FTree := Value;
If Assigned(FTree) Then
Begin
FTree.OnChange := OnTreeViewChange;
End;
end;
end.Форма (на форме только TreeView1 с созданными итемами для отладки): Код:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Unit2, Vcl.StdCtrls;
type
TForm1 = class(TForm)
TreeView1: TTreeView;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
FMyObj : TMyObject;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
FMyObj := TMyObject.Create;
FMyObj.Tree := TreeView1;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FMyObj.Free;
end;
end.Компилируется, ничего не падает, сообщение появляется. Собственно, что сделано по сути. Как и у тебя, есть аттрибут для ссылки на дерево (по традиции его имя начинается с 'F' (от Field). Вот только он является внутренним аттрибутом объекта и снаружи не виден (про дружественные классы мы тут не говорим, они вообще концепцию ООП нарушают ). Для доступа к этому полю созданно свойство Tree. У этого свойства есть геттер (read) и сеттер (write). В качестве геттера просто указано имя поля - нам не нужно ничего делать когда мы читаем поле, хотя там тоже можно добавить логику. А вот в качесве сеттера указан специальный метод класса (кстати, обрати внимание, что этот метод по умолчанию попадает в секцию private, иногда, если в наследниках предполагается его перекрытие, то его надо перенести хотя бы в секцию protected; тут читай теорию ООП какие секции наследуются), который не только присвоит принятое значение полю, но и настроит все обработчики событий (в данном случае только OnChange).Последний раз редактировалось lmikle, 14.10.2024 в 06:44. |
| Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
Guaho (14.10.2024)
| ||
|
#3
|
||||
|
||||
|
Оооо! Огромное спасибо!!! Это то, что нужно! Понятный пример с лаконичным объяснением! Суть понял, опробовал в своём прикидочном коде, ещё добавил объектов в класс по тем же принципам - работает замечательно! И сам код очень изящен, вообще у этого "классового" подхода своя чёткая логика построения, хотя и кажущаяся с непривычки несколько замысловатой )))
Очень странно, но я действительно нигде не нашёл даже упоминания о данном вопросе. А вопрос важнейший! |