【问题标题】:Delphi inheritance overlap: creating child see fatherDelphi继承重叠:创建孩子见父亲
【发布时间】:2017-09-04 06:04:57
【问题描述】:

是这样的:

3 involucated:一个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. 

祖先形态:

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.

子窗体:

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.

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.

子 Form 从祖先 Form 继承 myComponent。

创建时,子窗体会触发TMyComponent.Create() 构造函数,但AOwner.ComponentCount 看到的是祖先ComponentCount 而不是子窗体的ComponentCount

消息(来自myComponent.Something() 方法)显示:

"Hello Owner Name 是 myAncestor,Owner class 是 TMyChild,ComponentCount 是 1,myIdex 是 0,我的 name 是,我的 class 是 TMyComponent"

组件在子窗体中看不到edt1组件!!!

如何查看正确的 ComponentCount?

【问题讨论】:

标签: inheritance components delphi-xe8


【解决方案1】:

您的TMyComponent 对象看不到TEdit 对象,因为该对象尚未创建。您的 TMyComponent 对象首先被创建,因为它首先出现在子窗体的 DFM 中。

如果您希望您的组件在创建组件后检测何时创建TEdit,您可以让您的组件覆盖虚拟Notification() 方法。当一个组件被添加到所有者(或从所有者中删除)时,所有者会向其拥有的所有组件广播opInsert(或opRemove)通知。由于您的TMyComponentTEdit 对象具有相同的所有者,因此当TEdit 添加到表单的拥有组件列表中时,您的组件将收到opInsert 通知。

例如:

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. 

【讨论】:

  • 现在,另一个问题......该方法解决了插入组件的标识......但是......总是有一个但是......那个组件将是不完整的,例如。创建一个 dbgrid,但尚未创建列。我怎么知道什么时候都完成了?有可能吗?
  • @NizamUlMulk 当组件完成加载时(通过Loaded())通知组件,但在这种情况下组件之间没有广播通知。这将需要两个组件之间的直接通信。否则,您可以让您的组件向其自身发布一条异步消息,然后等待该消息由消息队列处理。 DFM 加载是同步操作,因此在收到消息时所有组件都已加载完毕。
  • 好的。谢谢雷米
  • 我以为我已经解决了,但是没有。通知只由所有者(祖先表单)触发,孩子永远不会向组件触发通知。如何访问子窗体中创建的控件或组件?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-04
  • 1970-01-01
  • 2019-02-23
  • 1970-01-01
  • 2019-10-16
  • 2013-08-19
相关资源
最近更新 更多