lyborko
lyborko

Reputation: 2619

Why loaded method is ignored?

I wonder why, but I can not simply debug my simple program. Loaded method is ignored, it is never executed. No idea why. Look:

    TGridObj = class (TComponent)
private
  FPen1:TPen;
  FBrush1:TBrush;
  FChange:TNotifyEvent;

protected
  procedure Loaded; override;


public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
published
  property OnChange:TNotifyEvent read FChange write FChange;

  property Pen1:TPen read FPen1 write FPen1;
  property Brush1:TBrush read FBrush1 write FBrush1;
end;

. . .

constructor TGridObj.Create(AOwner: TComponent);
  begin
  inherited Create(AOwner);
  FPen1:=TPen.Create;
  FPen1.OnChange:=FChange;


  FBrush1:=TBrush.Create;
  FBrush1.OnChange:=FChange;
  end;


destructor TGridObj.destroy;
  begin
  FPen1.Free;
  FBrush1.Free;
  inherited;
  end;

procedure TGridObj.Loaded();
begin
  inherited Loaded;
  ShowMessage('');   // this is never executed;
  FPen1.OnChange:=FChange;
  FBrush1.OnChange:=FChange;
end;

. .

procedure TForm1.FormCreate(Sender: TObject);
begin
Grid:=TGridObj.Create(nil);
Grid.OnChange:=ev1.OnChange;
Form1.InsertComponent(Grid);
end;

Thanx

Upvotes: 2

Views: 1721

Answers (2)

mjn
mjn

Reputation: 36664

OnLoaded will only be executed if the component is loaded from a form resource (dfm file).

If the component is created at run time in code only, it will not be executed.

Update:

I recommend to design components so that they can be created and configured at run time too - which means I avoid overriding OnLoaded. The advantage is that no package installation / component registration is needed.

Upvotes: 1

David Heffernan
David Heffernan

Reputation: 613302

Loaded is only called when the component's properties are streamed from the form file. Since you are creating it at runtime, Loaded does not get called. This is by design.

Your code needs some work anyway to allow for the OnChange event to be modified at runtime and have that change filter down to the pen and brush. I'd do it like this:

TGridObj = class (TComponent)
private
  FPen1: TPen;
  FBrush1: TBrush;
  FChange: TNotifyEvent;
  procedure DoChange(Sender: TObject);
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;
published
  property OnChange: TNotifyEvent read FChange write FChange;
  property Pen1: TPen read FPen1;
  property Brush1: TBrush read FBrush1;
end;

constructor TGridObj.Create(AOwner: TComponent);
begin
  inherited;
  FPen1 := TPen.Create;
  FPen1.OnChange := DoChange;
  FBrush1 := TBrush.Create;
  FBrush1.OnChange := DoChange;
end;

destructor TGridObj.Destroy;
begin
  FBrush1.Free;
  FPen1.Free;
  inherited;
end;

procedure TGridObj.DoChange(Sender: TObject);
begin
  if Assigned(FChange) then
    FChange(Sender);
end;

Now there's no need for Loaded or anything like that. Because you wait until the OnChange events of the pen and brush actually fire before accessing FChange.

By the way, in your code it's a mistake to add property setters for Pen1 and Brush1 that modify the underlying fields. That leads to leaks and all sorts of mess. Also, be warned that exposing the pen and brush as public properties allows clients of TGridObj to change the OnChange event. And that subverts TGridObj.OnChange.

Upvotes: 8

Related Questions