如何解开构造函数相互依赖的2个组件?

时间:2015-05-07 08:00:39

标签: delphi delphi-xe2

我正在使用this answer强制我自己的TPopupMenu超过标准窗口“剪切/复制/粘贴”上下文菜单。问题是我不知道如何布置OO结构来实现这一点。

unit BaseRamEditor.pas
type
  { This will override the default TStringGrid. }
  TStringGrid = class(Grids.TStringGrid)
  protected
    function CreateEditor: TInplaceEdit; override;
  end;

  TfrmBaseRamEditor = class(TForm)
    sgrSync: TStringGrid;
    RamEdPopup: TPopupMenu;

    procedure MenuItem1Click(Sender: TObject);

implementation

{$R *.dfm}

function TStringGrid.CreateEditor: TInplaceEdit;
{ Use our TPopupMenu instead of Windows default. }
begin
  Result := inherited CreateEditor;
  // XXX: I don't know how to reference the `RamEdPopup` object that belongs to
  // `TfrmBaseRamEditor`. I can't reference the `TfrmBaseRamEditor` instance
  // because it hasn't been created yet because it depends on THIS new
  // `TStringGrid`.
  TMaskEdit(Result).PopupMenu := RamEdPopup;
end;

以下是RamEdPopup中定义的BaseRamEditor.dfm。请注意,OnClick引用了TfrmBaseRamEditor方法

BaseRamEditor.dfm
=================
object frmBaseRamEditor: TfrmBaseRamEditor
    object RamEdPopup: TPopupMenu
        object MenuItem1: TMenuItem
            Caption = 'Diagramm 1'
            OnClick = MenuItem1Click
        end
    end
end

所以概述是:

  1. TfrmBaseRamEditor构造函数取决于被覆盖的TStringGrid
  2. TStringGrid构造函数取决于TPopupMenu的{​​{1}}。
  3. TfrmBaseRamEditor指向TPopupMenu
  4. 的方法

    如何解决这个混乱问题,以便TfrmBaseRamEditor中使用的TStringGrid使用frmBaseRamEditor

2 个答案:

答案 0 :(得分:5)

使用TStringGrid(TfrmBaseRamEditor)的所有者作为参考,并将其类型化为表单以访问RamEdPopup对象:

TMaskEdit(Result).PopupMenu := TfrmBaseRamEditor(Self.Owner).RamEdPopup;

如果要在运行时检查强制转换,请使用as内在函数:

TMaskEdit(Result).PopupMenu := (Self.Owner as TfrmBaseRamEditor).RamEdPopup;

答案 1 :(得分:5)

您可以在TStringGrid中创建其他属性,以便设置编辑器弹出菜单:

  TStringGrid = class(Grids.TStringGrid)
  protected
    FEditorPopup: TPopupMenu;
    function CreateEditor: TInplaceEdit; override;
    procedure SetEditorPopup(Value: TPopupMenu);
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  published
    property EditorPopup: TPopupMenu read FEditorPopup write SetEditorPopup;
  end;

function TStringGrid.CreateEditor: TInplaceEdit;
begin
  Result := inherited CreateEditor;
  TMaskEdit(Result).PopupMenu := FEditorPopup;
end;

procedure TStringGrid.SetEditorPopup(Value: TPopupMenu);
begin
  if Value <> FEditorPopup then
    begin
      if Assigned(FEditorPopup) then FEditorPopup.RemoveFreeNotification(Self);
      FEditorPopup := Value;
      if Assigned(FEditorPopup) then FEditorPopup.FreeNotification(Self);
      if Assigned(InplaceEditor) then TMaskEdit(InplaceEditor).PopupMenu := FEditorPopup;
    end;
end;

procedure TStringGrid.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (AComponent = FEditorPopup) then EditorPopup := nil;
end;

由于您要为默认的TStringGrid类创建inplace替换,因此在设计时使用已发布属性和设置EditorPopup的方法可能对您无效,但没有什么能阻止您设置EditorPopup属性在FormCreate事件中,在用户可以开始使用字符串网格之前。