Показать сообщение отдельно
  #2  
Старый 14.10.2024, 06:34
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,107
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Тут у тебя проблема с пониманием цикла жизни объектов. Ну или с пониманием сути объектных ссылок.
Судя по твоему коду, ты пытаешься установить обработчик события еще до того, как присваиваешь аттрибуту своего объекта ссылку на реально существующий контрол.

Вот так все работает:

Объект (упрощеный, только для демонстрации):
Код:
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).
Ответить с цитированием