如何解开构造函数相互依赖的 2 个组件?
How to untangle 2 components whose constructors depend on each other?
我正在使用 this answer 强制我自己的 TPopupMenu
超过标准 windows "Cut/Copy/Paste" 上下文菜单。问题是我不知道如何布置 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;
这里是在BaseRamEditor.dfm
中定义的RamEdPopup
。请注意,OnClick
引用了 TfrmBaseRamEditor
:
的 方法
BaseRamEditor.dfm
=================
object frmBaseRamEditor: TfrmBaseRamEditor
object RamEdPopup: TPopupMenu
object MenuItem1: TMenuItem
Caption = 'Diagramm 1'
OnClick = MenuItem1Click
end
end
end
所以概述是:
TfrmBaseRamEditor
构造函数依赖于重写的TStringGrid
- 这个
TStringGrid
构造函数依赖于TfrmBaseRamEditor
的TPopupMenu
。
- 这个
TPopupMenu
指向TfrmBaseRamEditor
的方法。
我怎样才能解决这个问题,以便 frmBaseRamEditor
中使用的 TStringGrid
使用 TPopupMenu
?
使用 TStringGrid
(TfrmBaseRamEditor)的所有者作为参考并将其类型转换为表单以访问 RamEdPopup
对象:
TMaskEdit(Result).PopupMenu := TfrmBaseRamEditor(Self.Owner).RamEdPopup;
如果要在运行时检查转换,请使用 as
内在函数:
TMaskEdit(Result).PopupMenu := (Self.Owner as TfrmBaseRamEditor).RamEdPopup;
您可以在 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
class 创建就地替换,因此在设计时使用已发布的 属性 和设置 EditorPopup
的方法可能对您不起作用,但没有任何作用在用户可以开始使用字符串网格之前阻止您在 FormCreate
事件中设置 EditorPopup
属性。
我正在使用 this answer 强制我自己的 TPopupMenu
超过标准 windows "Cut/Copy/Paste" 上下文菜单。问题是我不知道如何布置 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;
这里是在BaseRamEditor.dfm
中定义的RamEdPopup
。请注意,OnClick
引用了 TfrmBaseRamEditor
:
BaseRamEditor.dfm
=================
object frmBaseRamEditor: TfrmBaseRamEditor
object RamEdPopup: TPopupMenu
object MenuItem1: TMenuItem
Caption = 'Diagramm 1'
OnClick = MenuItem1Click
end
end
end
所以概述是:
TfrmBaseRamEditor
构造函数依赖于重写的TStringGrid
- 这个
TStringGrid
构造函数依赖于TfrmBaseRamEditor
的TPopupMenu
。 - 这个
TPopupMenu
指向TfrmBaseRamEditor
的方法。
我怎样才能解决这个问题,以便 frmBaseRamEditor
中使用的 TStringGrid
使用 TPopupMenu
?
使用 TStringGrid
(TfrmBaseRamEditor)的所有者作为参考并将其类型转换为表单以访问 RamEdPopup
对象:
TMaskEdit(Result).PopupMenu := TfrmBaseRamEditor(Self.Owner).RamEdPopup;
如果要在运行时检查转换,请使用 as
内在函数:
TMaskEdit(Result).PopupMenu := (Self.Owner as TfrmBaseRamEditor).RamEdPopup;
您可以在 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
class 创建就地替换,因此在设计时使用已发布的 属性 和设置 EditorPopup
的方法可能对您不起作用,但没有任何作用在用户可以开始使用字符串网格之前阻止您在 FormCreate
事件中设置 EditorPopup
属性。