TCollection i Notify

0

Witam ponownie

Macie jakiś pomysł na obsługę zdarzenia Notify dla kolekcji:

Notify(Item: TCollectionItem; Action: TCollectionNotification);

W elementach kolekcji odwołuję się do różnych komponentów i wypadałoby zwolnić referencję przed kasowaniem komponentu. Szukałem na necie ale naprawdę mało artykułów na ten temat

Pozdrawiam

0

nie bardzo rozumiem o co Ci chodzi. Chodzi Ci o usunięcie itema w momencie zwalniania obiektu czy o zwolnienie obiektu w momencie kasowania itema?

0

no generalnie w itemie jest odwołanie do komponentu i mogę dowolny komponent dziedziczący z TWinControl wybrać z listy. Teraz w przypadku gdy te odwołanie istnieje i kasuję komponent to wywala błąd. Problem polega na powiadomieniu itema, że dany komponent został wykasowany i przypisaniu właściwości nil, bądź całkowite usunięcie itema, tak jak zaznaczyłeś ;)

0

przecież TCollectionItem sam z siebie nie ma nawet gdzie przechowywać jakiegokolwiek odwołanie. Więc albo tak naprawdę masz swoje własne CollectionItem dziedziczące po TCollectionItem albo robisz coś pod górkę. Może daj chociaż ogólny zarys tego co chcesz zrobić, jakiś kawałek kodu jak dodajesz komponent do itema.

0

no ta dziedziczę oczywiście po TCollectionItem, ok więc:

 TNewFieldItem = class(TCollectionItem)
  private
    FField: TField;
    FWinControl: TWinControl;
    procedure SetField(Value: TField);
    procedure SetWinControl(Value: TWinControl);
  protected

  published
    property Field: TField read FField write SetField;
    property WinControl: TWinControl read FWinControl write SetWinControl;
  end;

  TNewFieldCollection = class(TCollection)
  private
    FComp: TComponent;
    FCollString: string;
  protected
    procedure Notify(Item: TCollectionItem; Action: TCollectionNotification); override;
  public
    constructor Create (CollOwner: TComponent);
    function GetOwner: TPersistent; override;
    procedure Update(Item: TCollectionItem); override;
  end;
0
constructor TNewFieldCollection.Create (CollOwner: TComponent);
begin
  inherited Create (TNewFieldItem);
  FComp := CollOwner;
end;

Tu jest konstruktor, a komponenty dodaje przez procedury Set**. Hmm może jakoś wysyłać do komponentu nadrzędnego polecenie FreeNotification ?

0

może jeszcze dodam, że kolekcja jest właściwością komponentu TNewDBNavigator:

constructor TNewDBNavigator.Create(AOwner: TComponent);
var
  i: TNewNavBtn;
begin

  inherited Create(AOwner);
  FColl := TNewFieldCollection.Create (Self);
....
1

to chyba najprościej będzie przez dosztukowanie :p

type
  TNotifier = class(TComponent)
  private
    FOnFreeWinControl: TNotifyEvent;
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation);
      override;
  public
    property OnFreeWinControl: TNotifyEvent read FOnFreeWinControl write FOnFreeWinControl;
  end;

  TNewFieldItem = class(TCollectionItem)
  private
    FField: TField;
    FWinControl: TWinControl;
    FNotifier: TNotifier;
    procedure NotifierFreeControl(Sender: TObject);
    procedure SetField(Value: TField);
    procedure SetWinControl(Value: TWinControl);
  protected

  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
  published
    property Field: TField read FField write SetField;
    property WinControl: TWinControl read FWinControl write SetWinControl;
  end;

implementation

{ TNewFieldItem }

constructor TNewFieldItem.Create(Collection: TCollection);
begin
  inherited;
  FNotifier := TNotifier.Create(nil);
end;

destructor TNewFieldItem.Destroy;
begin
  FNotifier.Free;
  inherited;
end;

procedure TNewFieldItem.NotifierFreeControl(Sender: TObject);
begin
  if Sender = FWinControl then
    FWinControl := nil;
end;

procedure TNewFieldItem.SetField(Value: TField);
begin
  //...
end;

procedure TNewFieldItem.SetWinControl(Value: TWinControl);
begin
  Value.FreeNotification(FNotifier); //!!WAŻNE
  //...
end;

{ TNotifier }

procedure TNotifier.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if Operation = opRemove then
    if Assigned(FOnFreeWinControl) then
      FOnFreeWinControl(AComponent);
end;

działa to tak, że ta linijka
Value.FreeNotification(FNotifier);
mówi komponentowi przekazanemu jako Value, że jak będziesz niszczony to masz wywołać metodę Notification obiektu przekazanego jako parametr (czyli FNotifier). BTW działa to w dwie strony, tzn jak zniszczysz FNotifier to Value się o tym dowie. I tyle.
A jako, iż, ponieważ, tudzież :p jest to mechanizm komponentów to TCollectionItem tego nie ma i trzeba to jakoś obejść. Najprościej jest stworzyć klasę, która dziedziczy po TComponent i dodać do niej zdarzenie, które będzie mogło być wyłapane przez dowolny obiekt, niezależnie po czym on dziedziczy.

0

Myślałem podobnie tylko nie bardzo wiedziałem jak obejść problem z parametrem FreeNotification, gdzie trzeba podać komponent. Dzięki wielkie Misiekd, działa jak marzenie : )

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.