Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I detect that a component has been freed?

Tags:

delphi

I have a component that I create and then pass into it a panel on my main form.

Here is a very simplified example:

procedure TMy_Socket.StatusPanel_Add(AStatusPanel: TPanel);

This component will then update the panels caption as the need arises.

In my main program if I FreeAndNil the panel the next time the component tries to update the panel I get an AV. I understand why: the component's reference to the panel now is pointing to an undefined location.

How can I detect within the component if the panel has been freed so I know I can not reference it?

I tried if (AStatusPanel = nil) but it is not nil, it still has an address.

like image 759
Steve Avatar asked Sep 19 '12 17:09

Steve


2 Answers

You have to call the Panel's FreeNotification() method, and then have your TMy_Socket component override the virtual Notification() method, eg (given your naming scheme, I assume you can add multiple TPanel controls to your component):

type
  TMy_Socket = class(TWhatever)
  ...
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  ...
  public
    procedure StatusPanel_Add(AStatusPanel: TPanel); 
    procedure StatusPanel_Remove(AStatusPanel: TPanel); 
  ...
  end;

procedure TMy_Socket.StatusPanel_Add(AStatusPanel: TPanel); 
begin
  // store AStatusPanel as needed...
  AStatusPanel.FreeNotification(Self);
end;

procedure TMy_Socket.StatusPanel_Remove(AStatusPanel: TPanel); 
begin
  // remove AStatusPanel as needed...
  AStatusPanel.RemoveFreeNotification(Self);
end;

procedure TMy_Socket.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if (AComponent is TPanel) and (Operation = opRemove) then
  begin
    // remove TPanel(AComponent) as needed...
  end;
end; 

If you are only tracking one TPanel at a time instead:

type
  TMy_Socket = class(TWhatever)
  ...
  protected
    FStatusPanel: TPanel;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  ...
  public
    procedure StatusPanel_Add(AStatusPanel: TPanel); 
  ...
  end;

procedure TMy_Socket.StatusPanel_Add(AStatusPanel: TPanel); 
begin
  if (AStatusPanel <> nil) and (FStatusPanel <> AStatusPanel) then
  begin
    if FStatusPanel <> nil then FStatusPanel.RemoveFreeNotification(Self);
    FStatusPanel := AStatusPanel;
    FStatusPanel.FreeNotification(Self);
  end;
end;

procedure TMy_Socket.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if (AComponent = FStatusPanel) and (Operation = opRemove) then
    FStatusPanel := nil;
end; 
like image 141
Remy Lebeau Avatar answered Nov 10 '22 10:11

Remy Lebeau


If your component needs to be notified when another component is freed, have a look at TComponent.FreeNotification. It should be just what you need.

like image 30
Mason Wheeler Avatar answered Nov 10 '22 08:11

Mason Wheeler