![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
TTreeView & OnChange [D7, XP]
mfender © (2006-03-06 10:05:00)Много искал, но что-то ничего толкового не нашёл.
Вобщем, ушнаследовал от TTreeView. С Click'ом всё получилось быстро и легко:
TmfTreeView = class(TTreeView)
protected
procedure Click; override;
end;
implementation
procedure TmfTreeView.Click;
begin
inherited Click;
Self.ChangeDataSet;
end;
Что можно сделать, чтобы унаследовать OnChange и добавить в обработчик своё? У меня не получается. Change - не виртуальный метод, а определённое событие TTVChangedEvent.
Ega23 (2006-03-06 11:36:00) [1]А в native-обработчике стоит
procedure TCustomTreeView.Change(Node: TTreeNode);
begin
if Assigned(FOnChange) then FOnChange(Self, Node);
end;
Так что действительно можно переопределить Change. Только inherited не забудь поставить...
mfender (2006-03-06 11:33:00) [2]
> Ещё раз: обработчик OnChange вызывается из динамического
> метода Change
Ок. Приму к сведению. Попробую ещё раз и так.
Спасибо.
Ega23 (2006-03-06 11:29:00) [3]
> Вот так и писал:
> procedure Change(Sender: TObject; Node: TTreeNode); override;
>
> В ответ мне - ошибка, про то, что объявление метода Change
> не похоже на оригинальный метод.
Конечно ругаться будет. Ибо:
procedure Change(Node: TTreeNode); dynamic;
begin...end (2006-03-06 11:29:00) [4]> mfender © (06.03.06 11:25) [10]
А Sender-то откуда взялся? Ещё раз: обработчик OnChange вызывается из динамического метода Change . Его можно перекрыть:
TMyTreeView = class(TCustomTreeView)
protected
procedure Change(Node: TTreeNode); override;
end
и, кроме вызова метода родителя (а значит, и вызова обработчика OnChange) делать в нём ещё что-нибудь.
mfender (2006-03-06 11:25:00) [5]
> Не понял. Как пробовали? Что ожидали? Что не получилось?
Вот так и писал:
procedure Change(Sender: TObject; Node: TTreeNode); override;
В ответ мне - ошибка, про то, что объявление метода Change не похоже на оригинальный метод.
begin...end (2006-03-06 11:14:00) [6]> mfender © (06.03.06 11:10) [8]
Не понял. Как пробовали? Что ожидали? Что не получилось?
Да, в [7] Change нужно в protected разместить. Забыл...
mfender (2006-03-06 11:10:00) [7]
> Не виртуальный, но динамический. Так что проблем с перекрытием
> не вижу.
Вот именно так я и пытался, но ничего не получилось.
begin...end (2006-03-06 11:07:00) [8]> mfender © (06.03.06 10:05)
> Change - не виртуальный метод
Не виртуальный, но динамический. Так что проблем с перекрытием не вижу.
TMyTreeView = class(TCustomTreeView)
procedure Change(Node: TTreeNode); override;
end;
procedure TMyTreeView.Change(Node: TTreeNode);
begin
...
inherited;
...
end
mfender (2006-03-06 11:04:00) [9]
> А ты загляни в исходники TTreeView. Это всего-лишь обёртка
> вокруг TCustomTreeView. В нём (TTReeView) никакой логики
> не зашито, только определены public, private и published
> свойства.
Заглядывал. Именно с этого я и начал. Впрочем, мысль один раз была, унаследовать от TCustomTreeView.
> Казалось бы - что проще: взять и в ран-тайме подменить эти
> обработчики своими. Но тогда, если у тебя 2 экземпляра твоего
> компонента, "смотрящие" на один и тот же НД - ты получишь
> полную ерунду, т.к. "захватит" НД последний созданный. А
> если кто-то ещё раньше этот обработчик определил?
Вот потому и решился написать свой DBTreeView. Ибо изначально я понаписал прямо в основном юните столько, что сам ничего уже не понимаю по прошествии двух месяцев.)))
Ещё раз спасибо!
Ega23 (2006-03-06 10:58:00) [10]
> Кстати, а почему наследовать лутше от TCustomTreeView?
А ты загляни в исходники TTreeView. Это всего-лишь обёртка вокруг TCustomTreeView. В нём (TTReeView) никакой логики не зашито, только определены public, private и published свойства.
> Олег, т.е. со всеми событиями так и поступать в дальнейшем?
Это если оно тебе надо.
Вот пример, так сказать, "на пальцах":
Ты пишешь свой DB-компонент. По каким-то причинам решил не пользоваться той идеологией, которую Borland предлагает (TDataSet->TDataSource->TDataLink). Имеешь на это право.
Но в таком случае тебе нужно знать следующие вещи:
1. Когда набор данных изменил свойство Active (открылся - закрылся)
2. Когда в наборе данных поменялась позиция курсора.
Есть ещё, но первых двух для начала вполне достаточно.
Теоретически, всю эту информацию ты можешь вытащить, написав обработчики TDataSet.OnScroll (или AfterScroll, точно не помню) и TDataSet.OnAfterOpen.
Казалось бы - что проще: взять и в ран-тайме подменить эти обработчики своими. Но тогда, если у тебя 2 экземпляра твоего компонента, "смотрящие" на один и тот же НД - ты получишь полную ерунду, т.к. "захватит" НД последний созданный. А если кто-то ещё раньше этот обработчик определил?
Вот для этого ты и запоминаешь указатель на предыдущий обработчик, и если он не nil - вызываешь его, а потом исполняешь собственный код. В общем, некий аналог inherited.
mfender (2006-03-06 10:34:00) [11]Олег, т.е. со всеми событиями так и поступать в дальнейшем?
Кстати, а почему наследовать лутше от TCustomTreeView?
mfender (2006-03-06 10:29:00) [12]Спасибо, Дружище!
Ega23 (2006-03-06 10:27:00) [13]Совет: наследуйся не от TTreeView, а от TCustomTreeView.
Ega23 (2006-03-06 10:26:00) [14]
TmfTreeView = class(TTreeView)
FTreeViewOnChange:TTVChangedEvent;
protected
constructor Create(AOwner:TComponent);
procedure TreeViewOnChange(Sender: TObject; Node: TTreeNode);
end;
constructor TmfTreeView.Create(AOwner:TComponent);
begin
FTreeViewOnChange:=Self.OnChange; // Запоминаем, определён ли базовый OnChange;
Self.OnChange:=TreeViewOnChange; // Подставляем собственный обработчик
end;
procedure TmfTreeView.TreeViewOnChange(Sender: TObject; Node: TTreeNode);
begin
if assigned(FTreeViewOnChange) then
FTreeViewOnChange(Sender, Node); // Если базовый был определён, то выполняем его.
/////// Тут уже свои навороты
end;
В целом так.