Форум: "Основная";
Текущий архив: 2002.08.15;
Скачать: [xml.tar.bz2];
Вниз
Проблема с Notification Найти похожие ветки
← →
evgeg (2002-08-04 11:05) [0]Здраствуйте!
Мне нужно задавать в design-time для своего компонента TMyComponent1 дин. список из ссылок на др. компоненты TMyComponent2.
Сделал свойство типа TMyColl -- наследник от TCollection, элементами которого является TMyItem - наследник от TCollectionItem, у которого есть published свойство типа TMyComponent2. Сделал редактор для свойства TMyColl, работает.
Проблема: Метод TMyComponent1.Notification вызывается, если удаляемый TMyComponent2 лежит на той же форме, и НЕ вызывается, если TMyComonent2 лежит на другой форме, хотя этот другой модуль подкляючен к модулю формы, на которой лежит TMyComponent1 и, следовательно, ссылка на него может ставится в список MyColl.Item.MyComponent.
В результате - Access Violation.
Что делать?
С уважением, Евгений.
← →
evgeg (2002-08-04 11:06) [1]> MyColl.Item.MyComponent
MyColl.Items[i].MyComponent
← →
Старый паскалист (2002-08-04 11:35) [2]Когда компоненты лежат на одной форме (точнее, когда у них один owner) - компонент при уничтожении уведомляет owner"a, а тот ретранслирует уведомление всем своим компонентам.
Если же не лежат - у TComponent есть специальный список FFreeNotifies, в который добавляются компоненты, которые должны быть уведомлены о его уничтожении и которые не лежат на той же форме.
Их надо добавлять туда с помощью метода
procedure TComponent.FreeNotification(AComponent: TComponent);
(он делает взаимное добавление)
← →
Старый паскалист (2002-08-04 11:49) [3]Проще говоря,
procedure TMyComponent1.SetMyComponent2(Value: TMyComponent2);
begin
FMyComponent2 := Value;
if Assigned(Value) then FreeNotification(Value);
end;
← →
Старый паскалист (2002-08-04 12:02) [4]Пардон, для твоего случая
procedure TMyItem.SetMyComponent2(Value: TMyComponent2);
begin
FMyComponent2 := Value;
if Assigned(Value) then
(Collection.GetOwner as TComponent).FreeNotification(Value);
end;
← →
Юрий Зотов (2002-08-04 12:47) [5]1. Я бы написал так.
procedure TMyComponent1.SetMyComponent2(Value: TMyComponent2);
begin
if FMyComponent2 <> Value then
begin
// Для D5 и выше эта строка не будет лишней
if Assigned(FMyComponent2) then (FMyComponent2);
FMyComponent2 := Value;
if Assigned(Value) then FreeNotification(Value)
end
end;
2. Стандартный механизм уведомлений реализован только в компонентах. В Вашем же случае уведомления нужны НЕкомпонентскому классу TMyItem, поэтому такой механизм придется делать ручками. В подобных случаях я использую следующую схему.
а). В методе TMyItem.Set... (см. выше) cвязываю полученную ссылку на компонент с компонентом - владельцемм коллекции. То есть, не FreeNotification (у TMyItem такого метода просто нет), а так:
TComponent(Collection.Owner).RemoveFreeNotification(...)
TComponent(Collection.Owner).FreeNotification(Value)
б). В TMyItem ввожу метод Notification (по образцу и подобию TComponent). Он делает нужную проверку и очищает ссылку.
в). Такой же метод ввожу в TMyColl. Он лишь обзванивает элементы коллекции (в цикле вызывает их методы Notification). Но с обязательной предварительной проверкой:
if not (csDestroying in TComponent(Owner).ComponentState) then...
Иначе можно нарваться на неприятности (суть рассказывать долго, но это так - уже проверено).
г). Последний шаг: в методе Notification компонента - владельца коллекции вызвать метод Notification самой коллекции.
Вот и все. Могу лишь добавить, что по этой схеме был реализован, наверное, уже с десяток коллекций. Все работает нормально (да и чему бы там не работать?).
← →
Юрий Зотов (2002-08-04 12:49) [6]Пардон, слово пропустил. Следует читать так:
// Для D5 и выше эта строка не будет лишней
if Assigned(FMyComponent2) then RemoveFreeNotification(FMyComponent2);
← →
Старый паскалист (2002-08-04 13:04) [7]2Юрий Зотов
Я заметил, в VCL нигде не делается RemoveFreeNotification при замене одного компонента на другой.
Это, вероятно, связано с тем, что компонент может иметь не одно св-во, ссылающееся на один и тот же компонент (И более того, если его нет - оно может возникнуть в потомке), и корректно отследить это в предках невозможно, а отдавать на откуп программистам - опасно. В результате, что попало в FFreeNotifies - то останется там до скончания веков (или пока осёл или падишах не умрёт). :-(((
← →
Юрий Зотов (2002-08-04 13:14) [8]> Старый паскалист (04.08.02 13:04)
Да, я тоже это заметил, тоже думал "почему?" и тоже пришел к тому же выводу. Но я пишу компоненты для себя, а поэтому всегда точно знаю, что и где происходит. Соответственно, могу позволить себе такую роскошь, как отцепление от уже ненужной (и, возможно, очень длинной) цепочки совершенно лишних операций.
Хотя упомянуть об этом действительно стоило. Хорошо, что Вы это сделали.
← →
evgeg (2002-08-04 20:37) [9]> Старый паскалист
> Юрий Зотов
Спасибо большое за помощь!
Однако, возникла еще одна проблема. У TMyColl я сделал поле FMyComponent1, ссылающееся на компонент-владелец. (Пишу в Дельфи 2, у нее нет св-ва Owner в TCollection). Сделал проверку в TMyColl.Notification (которая вызывается из TMyComponent.Notification), как рекомендовано в <Юрий Зотов © (04.08.02 12:47)> :
if not (csDestroying in FMyComponent1.ComponentState) then...
Возникает Access Violation, при помещении компонента TMyComponent1 на форму. Если проверку убрать, то Access Violation не возникает. Выяснилось, что ЛЮБОЕ обращение к FMyComponent1 в TMyColl.Notification вызывает такую ошибку. Например:
if Assigned (FMyComponent1) ..
if (FMyComponent1 <> nil) ...
ShowMessage (Format ("%p",[Self.FMyComponent1]));
Просто чудеса какие то! Что посоветуете?
← →
Юрий Зотов (2002-08-04 21:32) [10]А где и как инициализируется поле FMyComponent1 ?
← →
Юрий Зотов (2002-08-04 23:18) [11]Кажется, понял. Причина, по-видимому, в том, что в конструкторе компонента сначала вызывается inherited, а потом создается коллекция. Соответственно, цепочка уведомлений отрабатывает слишком рано.
Выход простой - добавьте проверку в Notification компонента:
if AComponent <> Self then
FMyColl.Notification(AComponent, Operation);
Честно говоря, это мое упущение, надо было вспомнить раньше. Sorry.
← →
evgeg (2002-08-05 08:24) [12]> Юрий Зотов
Спасибо! Все заработало.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2002.08.15;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.006 c