如何在复合组件中发布子组件的属性?

时间:2017-05-11 12:23:20

标签: delphi components

在从TPanel派生的复合组件中,我试图发布一个属性,该唯一的pourpose是设置并获取子组件的链接属性。每次我将复合组件添加到表单时,都会引发访问冲突:

  

模块“MyRuntimePackage.bpl”中地址12612D86处的访问冲突。读取地址00000080。

我准备了一个使用TLabel及其PopupMenu属性的简化示例,但在将复合组件放置在表单/框架上时仍然存在同样的问题。

运行时包:

uses
  StdCtrls, Menus, ExtCtrls, Classes;

type
  TTestCompoundComponent = class(TPanel)
  private
    FSubCmp : TLabel;
    function    GetLabelPopupMenu() : TPopupMenu;
    procedure   SetLabelPopupMenu(AValue : TPopupMenu);
  protected
    procedure   Notification(AComponent: TComponent; Operation: TOperation); override;
  public
    constructor Create(AOwner : TComponent); override;
    destructor  Destroy(); override;
  published
    property    LabelPopupMenu : TPopupMenu read GetLabelPopupMenu write SetLabelPopupMenu;
  end;

...

function    TTestCompoundComponent.GetLabelPopupMenu() : TPopupMenu;
begin
  Result := FSubCmp.PopupMenu;
end;

procedure   TTestCompoundComponent.SetLabelPopupMenu(AValue : TPopupMenu);
begin
  if(GetLabelPopupMenu() <> AValue) then
  begin
    if(GetLabelPopupMenu() <> nil)
    then GetLabelPopupMenu().RemoveFreeNotification(Self);

    FSubCmp.PopupMenu := AValue;

    if(GetLabelPopupMenu() <> nil)
    then GetLabelPopupMenu().FreeNotification(Self);
  end;
end;

procedure   TTestCompoundComponent.Notification(AComponent: TComponent; Operation: TOperation);
begin      
  inherited;
  if((AComponent = GetLabelPopupMenu()) AND (Operation = opRemove))
  then SetLabelPopupMenu(nil);
end;

constructor TTestCompoundComponent.Create(AOwner : TComponent);
begin
  inherited;
  FSubCmp := TLabel.Create(nil);
  FSubCmp.Parent := Self;
end;

destructor TTestCompoundComponent.Destroy();
begin
  FSubCmp.Free;
  inherited;
end;

Designtime包:

procedure Register;
begin
  RegisterComponents('MyTestCompoundComponent', [TTestCompoundComponent]);
end;

1 个答案:

答案 0 :(得分:5)

GetLabelPopupMenu() FSubCmp nil Notification() opInsert FSubCmp FSubCmp {}}}如果nilPopupMenu,则引用其GetLabelPopupMenu()属性将导致AV。因此,您需要在if FSubCmp = nil then Result := nil else Result := FSubCmp.PopupMenu; 中检查,例如:

and

否则,请将Notification()if (Operation = opRemove) and (AComponent = GetLabelPopupMenu()) 逻辑的顺序改为:

(Operation = opRemove)

如果条件<p>(.*?);(.*?)<p>为假,则不会评估右侧条件(短路)。