Отловить событие при добавлении дочерних
Модератор: Модераторы
Отловить событие при добавлении дочерних
Задача: поймать и обработать добавляемый контрол в некоторый контейнер.
Например: есть форма. На форму программно добавляют контрол.
Вопрос: где и как можно получить этот добавляемый контрол, и выполнить при этом некоторые действия над ним?
Вопрос-дополнение, по типу P.S.:
У любого TWinControl есть метод: InsertControl(AControl: TControl); и InsertControl(AControl: TControl; Index: integer); virtual;. Ясное дело, что в потомке мы можем перекрыть этот метод. Но как повесить свой обработчик на это событие?
Например: разместим на форме свой компонент (TMyComponent). В нём опишем действия над контролом, который будет добавляться на форму программно. Как это действие привязать к событию: "добавление на форму некоторого компанента"?
P.P.S.: понимаю, что объяснил не слишком доходчиво. Готов разжевать проблему до любой степени, лишь бы решить задачу...
Спасибо!
Например: есть форма. На форму программно добавляют контрол.
Вопрос: где и как можно получить этот добавляемый контрол, и выполнить при этом некоторые действия над ним?
Вопрос-дополнение, по типу P.S.:
У любого TWinControl есть метод: InsertControl(AControl: TControl); и InsertControl(AControl: TControl; Index: integer); virtual;. Ясное дело, что в потомке мы можем перекрыть этот метод. Но как повесить свой обработчик на это событие?
Например: разместим на форме свой компонент (TMyComponent). В нём опишем действия над контролом, который будет добавляться на форму программно. Как это действие привязать к событию: "добавление на форму некоторого компанента"?
P.P.S.: понимаю, что объяснил не слишком доходчиво. Готов разжевать проблему до любой степени, лишь бы решить задачу...
Спасибо!
Если я правильно понял, что требуется:
Код: Выделить всё
unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls;
type
TOnCtrlInsert = procedure(aSender: TObject; aControl: TControl) of object;
TForm = class(Forms.TForm)
private
FOnCtrlInsert: TOnCtrlInsert;
public
procedure InsertControl(aControl: TControl; aIndex: Integer); override;
property OnControlInsert: TOnCtrlInsert read FOnCtrlInsert write FOnCtrlInsert;
end;
THelpComp = class(TComponent)
public
procedure ControlInserted(aSender: TObject; aControl: TControl);
end;
TfrmMain = class(TForm)
btAdd: TButton;
procedure btAddClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
public
HelpComp: THelpComp;
end;
var
frmMain: TfrmMain;
implementation
{$R *.lfm}
{ TfrmMain }
procedure TfrmMain.btAddClick(Sender: TObject);
var
Pane: TPanel;
begin
Pane := TPanel.Create(Self);
Pane.Parent := Self;
end;
procedure TfrmMain.FormCreate(Sender: TObject);
begin
HelpComp := THelpComp.Create(Self);
OnControlInsert := @HelpComp.ControlInserted;
end;
{ THelpComp }
procedure THelpComp.ControlInserted(aSender: TObject; aControl: TControl);
begin
ShowMessage('Inserted control ' + aControl.ClassName);
end;
{ TForm }
procedure TForm.InsertControl(aControl: TControl; aIndex: Integer);
begin
inherited InsertControl(aControl, aIndex);
if Assigned(FOnCtrlInsert) and (Controls[aIndex] = aControl) then
FOnCtrlInsert(Self, aControl);
end;
end.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Последний раз редактировалось iskander 22.04.2019 07:22:43, всего редактировалось 2 раза.
На моём примере, когда мне нужно поставить свой обработчик для мыши.
procedure IconMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer);
Код: Выделить всё
...
procedure IconMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer);
...
procedure TDIcon.InitMouse;
begin
OnMouseDown := @IconMouseDown;
OnMouseEnter := @IconMouseEnter;
OnMouseLeave := @IconMouseLeave;
end;
procedure IconMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer);
iskander писал(а):Если я правильно понял, что требуется
Вы наследуетесь от формы. Такой подход сейчас у меня тоже используется. Но это не удобно. Ищу способ типа такого:
- используется форма по умолчанию;
- на форму кидается самописный компонент на основе TComponent (TMyAnyComponent) в режиме дизайна формы;
- если на форме есть уже контролы, то в приватном поле у TMyAnyComponent создаем массив из нужных FArrControls: array of TControls; (тут нет проблем);
- если во время дизайна в будущем разработчик добавит еще один контрол на обычную форму, то нужно как-то узнать об этом событии, и при необходимости добавить этот контрол в массив TMyAnyComponent.FArrControls (вот тут я не могу сообразить - как?);
- если во время выполнения приложения на стандартную обычную форму программно будет добавлен новый контрол (TControl), то тоже при необходимости добавить его в массив TMyAnyComponent.FArrControls.
- так же требуется отследить удаление с формы контролов.
P.S. При этом TMyAnyComponent может быть добавленным и на TPanel или TFrame, - любой контейнер. И тогда он будет отслеживать только те контролы, которые добавляются/удаляются в этом контейнере.
Добавлено спустя 3 минуты 41 секунду:
sign писал(а):На моём примере, когда мне нужно поставить свой обработчик для мыши.
Вот если бы было у TWinControl свойство OnSetControl или OnSetControlParent, которые бы обрабатывались во время инсерта контрола в контейнер или когда этому контролу назначают парентом данный контейнер, - то и вопроса бы не возникало. Но может я что-то и пропустил по незнанию...
VirtUX писал(а):Но это не удобно
Почему? Это никак не мешает дизайнеру форм.
VirtUX писал(а):требуется отследить удаление с формы контролов
Ничто не мешает добавить такой же перехватчик для RemoveControl.
Последний раз редактировалось iskander 22.04.2019 07:40:00, всего редактировалось 1 раз.
- Лекс Айрин
- долгожитель
- Сообщения: 5723
- Зарегистрирован: 19.02.2013 16:54:51
- Откуда: Волгоград
- Контактная информация:
iskander, видимо потому что придется делать для каждого окна свое добавление. А это сразу куча дублирующегося кода.
Лекс Айрин писал(а):iskander, видимо потому что придется делать для каждого окна свое добавление. А это сразу куча дублирующегося кода.
Да, совершенно верно. Хочу избавиться от этой постоянной вставки "костылей". Можно, конечно, влезть в исходник самого TWinControl и добавить туда необходимые OnSetControl или что-то наподобие. И если другого решения не найдется, то так и придется сделать. Но не хотелось бы... Может есть способ как-то повесить обработчик события на что-то, что выполняется до или после SetControl?
Хозяин-барин...
Если не трудно, отпишитесь, как получилось решить проблему.
Если не трудно, отпишитесь, как получилось решить проблему.
Как я понял речь идет о том, чтобы иметь централизованное место, где собирается информация о создании/удалении определенных компонентов. Мне кажется можно сделать чтобы при создании/удалении создавалось сообщение типа WM_USER+... а в центрохранилище организовать их обработку
Задача повесить обработчик на контейнер (TPanel, TForm, TGroupBox, etc), который обрабатывал бы добавление/удаление контрола в этом контейнере. При этом вешать на стандартные контейнеры, а не на переопределенные в наследниках. Сейчас мне приходится переопределять стандартные (TAnyPanel = class(TPanel), TAnyGroupBox = class(TGroupBox), etc) и в них реализовать необходимые свойства (property OnInsertControl, property OnRemoveControl), на которые я вешаю свои обработчики (pAnyPanel.OnInsertControl:= @OtherComponent.CheckInsertedControl;). Но было бы гораздо проще, если бы можно было отлавливать добавление/удаление в контейнере, без его переопределения в новый класс...
- Лекс Айрин
- долгожитель
- Сообщения: 5723
- Зарегистрирован: 19.02.2013 16:54:51
- Откуда: Волгоград
- Контактная информация:
VirtUX, стоп, но есть же какое-то сообщение, которое вызывается при смене количества дочерних элементов. Сейчас точно не скажу, так как книжку потерял при переезде, но думаю порывшись в поисковике найти можно. Тогда нужно будет просто повесить его обработчик на контейнер. И веди точно что-то подобное видел.
Добавлено спустя 9 минут 45 секунд:
Попробуй посмотреть тут http://fegorsk.ru/index.php/studentam/d ... enty-formy
Это правда для Дельфи, но принцип должен быть одинаковым. А для проверки лежит он на контейнере или нет можно проверять свойство parent.
Добавлено спустя 9 минут 45 секунд:
Попробуй посмотреть тут http://fegorsk.ru/index.php/studentam/d ... enty-formy
Это правда для Дельфи, но принцип должен быть одинаковым. А для проверки лежит он на контейнере или нет можно проверять свойство parent.
VirtUX писал(а):(TAnyPanel = class(TPanel), TAnyGroupBox = class(TGroupBox), etc)
??? И создаете их все в runtime ?
Похоже вы не смотрели внимательно мой пример, этот фокус
Код: Выделить всё
TForm = class(Forms.TForm)
позволяет вполне себе формошлепствовать и редактировать свойства компонентов в инспекторе объектов без перекомпиляции LCL.
В аттаче пример, который делает примерно то, что вы описали.
Без особого изящества, при необходимости допилите напильником.
Прежде чем открывать проект, нужно установить в IDE компонент из папочки wcobserver.
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Лекс Айрин писал(а):есть же какое-то сообщение, которое вызывается при смене количества дочерних элементов
Вот знать бы - какое? Я перерыл довольно много, но так и не нашел. Возможно, не там искал, или не то искал. Поэтому и задал вопрос тут.
Лекс Айрин писал(а):Попробуй посмотреть тут
Это про простой перебор компонентов. И про управление списком оных.
iskander писал(а):создаете их все в runtime ?
Нет. Всё описанное выше относится ко времени дизайна (верстки) в среде Lazarus (ну ко времени Run тоже, как само разумеещееся). Мне нужно отловить событие, когда разработчик добавляет любой компонент (в действительности интересуют только контролы) на стандартный (имеющийся в списке компонент в Lazarus сразу после его установки) контейнер (типа TPanel, TForm, TFrame, etc). Вот и всё.
Сейчас приходится перед началом разработки приложения устанавливать дополнительный пакет с переопределенными мной контейнерами. Так сказать - врапперы на стандартные TPanel, TGroupBox и т.п. Ищу способ, чтобы не делать этого, и получить возможность отлавливать изменения с дочерними у обычных, стандартных контейнеров, которые идут по умолчанию в среде разработки Lazarus.
Добавлено спустя 2 минуты 47 секунд:
Я понимаю, что можно подправить исходники классов и пересобрать Lazarus. Но это слишком радикальный и не совсем удобный способ
- Снег Север
- долгожитель
- Сообщения: 3067
- Зарегистрирован: 27.11.2007 15:14:47
- Контактная информация:
VirtUX писал(а): получить возможность отлавливать изменения с дочерними у обычных, стандартных контейнеров,
Такого нет. Попробуйте хелперы, что ли.
Снег Север писал(а):Попробуйте хелперы, что ли.
Полагаю, хелперы здесь не помогут.
VirtUX писал(а):устанавливать дополнительный пакет с переопределенными мной контейнерами
VirtUX, а вы в пример заглядывали?
