-1

This is the case:

3 involucrated: a myComponent component, an ancestor form and a child form: (edited)

MyComponent:

unit Component1;

interface

uses
  System.SysUtils, System.Classes, Vcl.Dialogs;

type
  TMyComponent = class(TComponent)
  private
    { Private declarations }
    procedure Something(i: Integer);
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TMyComponent]);
end;

{ TMyComponent }

constructor TMyComponent.Create(AOwner: TComponent);
var
  i: integer;
begin
  inherited Create(AOwner);
  if AOwner.ComponentCount > 0 then
    for i := 0 to AOwner.ComponentCount -1 do
      Something(i);
end;

procedure TMyComponent.Something(i: Integer);
var
  txt: string;
begin
  txt := Format('Owner Name is %s, Owner Class is %s, ComponentCount is %d,'+
    'myIndex is %d, My name is %s, my class is %s',
  [Owner.Name, Owner.ClassName, Owner.ComponentCount, i, Owner.Components[i].Name,
    Owner.Components[i].ClassName]);
  ShowMessage('Hello '+txt);
end;

end. 

The ancestor Form:

unit Ancestor;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Component1;

type
  TmyAncestor = class(TForm)
    MyComponent1: TMyComponent;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  myAncestor: TmyAncestor;

implementation

{$R *.dfm}

end.

The child Form:

unit TheChild;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Ancestor, Vcl.StdCtrls, Component1;

type
  TmyChild = class(TmyAncestor)
    edt1: TEdit;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  myChild: TmyChild;

implementation

{$R *.dfm}

end.

The dpr:

program InheritanceTest;

uses
  Vcl.Forms,
  Ancestor in 'Ancestor.pas' {myAncestor},
  TheChild in 'TheChild.pas' {myChild};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TmyChild, myChild);
  Application.Run;
end.

The child Form inherits myComponent from the ancestor Form.

When created, the child Form triggers the TMyComponent.Create() constructor, but AOwner.ComponentCount see the ancestor ComponentCount and not the child's ComponentCount.

The message (from the myComponent.Something() method) shows this:

"Hello Owner Name is myAncestor, Owner class is TMyChild, ComponentCount is 1, myIdex is 0, My name is , my class is TMyComponent"

The component does not see the edt1 component in the child form!!!

How can I see the correct ComponentCount?

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
NizamUlMulk
  • 386
  • 1
  • 4
  • 21

1 Answers1

0

Your TMyComponent object does not see the TEdit object because that object simply hasn't been created yet. Your TMyComponent object is being created first, as it appears first in the child Form's DFM.

If you want your component to detect when the TEdit is created after your component has been created, you can have your component override the virtual Notification() method. When a component is added to (or removed from) an Owner, the Owner broadcasts an opInsert (or opRemove) notification to all components that it owns. Since your TMyComponent and TEdit objects have the same Owner, your component will receive an opInsert notification when the TEdit is added in the Form's list of owned components.

For example:

unit Component1;

interface

uses
  System.SysUtils, System.Classes, Vcl.Dialogs;

type
  TMyComponent = class(TComponent)
  private
    { Private declarations }
    procedure Something(const FromWhere: string; Index: Integer);
  protected
    { Protected declarations }
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TMyComponent]);
end;

{ TMyComponent }

constructor TMyComponent.Create(AOwner: TComponent);
var
  i: integer;
begin
  inherited Create(AOwner);
  if AOwner <> nil then
  begin
    for i := 0 to AOwner.ComponentCount-1 do
      Something(`Create`, i);
  end;
end;

procedure TMyComponent.Notification(AComponent: TComponent; Operation: TOperation);
var
  i: integer;
begin
  inherited;
  if (Operation = opInsert) and (AComponent <> Self) and (AComponent.Owner = Owner) then
    Something('Notification', AComponent.ComponentIndex);
end;

procedure TMyComponent.Something(const FromWhere: string; Index: Integer);
var
  txt: string;
begin
  txt := Format('Owner Name is %s, Owner Class is %s, ComponentCount is %d, myIndex is %d, My name is %s, my class is %s',
    [Owner.Name, Owner.ClassName, Owner.ComponentCount, Index, Owner.Components[Index].Name, Owner.Components[Index].ClassName]);
  ShowMessage(FromWhere + ',' + txt);
end;

end. 
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Now, another question .... that method resolves identification for inserted component... but .... always is there a but ... that component would be incomplete, ex. creating a dbgrid, but the columns not yet. How can I know when all is complete?, is it possible? – NizamUlMulk Apr 12 '17 at 14:09
  • @NizamUlMulk A component is notified (via `Loaded()`) when itself has finished loading, but there is no notification broadcasted between components in that situation. That would require direct communication between the two components. Otherwise, you could have your component post an asynchronous message to itself and then wait for that message to be processed by the message queue. DFM loading is a synchronous operation, so all components will have been loaded by the time the message is received. – Remy Lebeau Apr 12 '17 at 15:15
  • I thought i was solved, but No. Notification only are fired by the Owner (the Ancestor form), the child never fires notification to the component. How can I access to the controls or components created in child form? – NizamUlMulk May 14 '17 at 02:00