I'm using this answer to force my own TPopupMenu
over the standard windows "Cut/Copy/Paste" context menu. The problem is I don't know how to lay out the OO structure to allow this.
我正在使用这个答案强制我自己的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;
Here is the RamEdPopup
defined in the BaseRamEditor.dfm
. Notice that the OnClick
references a method of TfrmBaseRamEditor
:
这是BaseRamEditor.dfm中定义的RamEdPopup。请注意,OnClick引用了TfrmBaseRamEditor的方法:
BaseRamEditor.dfm
=================
object frmBaseRamEditor: TfrmBaseRamEditor
object RamEdPopup: TPopupMenu
object MenuItem1: TMenuItem
Caption = 'Diagramm 1'
OnClick = MenuItem1Click
end
end
end
So the overview is:
所以概述是:
- The
TfrmBaseRamEditor
constructor depends on the overriddenTStringGrid
- This
TStringGrid
constructor depends on theTPopupMenu
ofTfrmBaseRamEditor
. - This
TPopupMenu
points to the methods ofTfrmBaseRamEditor
.
TfrmBaseRamEditor构造函数依赖于重写的TStringGrid
此TStringGrid构造函数依赖于TfrmBaseRamEditor的TPopupMenu。
这个TPopupMenu指向TfrmBaseRamEditor的方法。
How can I untangle this mess so that the TStringGrid
used in frmBaseRamEditor
uses the TPopupMenu
?
我如何解决这个混乱,以便frmBaseRamEditor中使用的TStringGrid使用TPopupMenu?
2 个解决方案
#1
Use the owner of the TStringGrid
(the TfrmBaseRamEditor) as the reference and typecast it to the form to access the RamEdPopup
object:
使用TStringGrid的所有者(TfrmBaseRamEditor)作为引用并将其类型转换为表单以访问RamEdPopup对象:
TMaskEdit(Result).PopupMenu := TfrmBaseRamEditor(Self.Owner).RamEdPopup;
If you want to check the cast at runtime, use the as
intrinsic:
如果要在运行时检查强制转换,请使用as intrinsic:
TMaskEdit(Result).PopupMenu := (Self.Owner as TfrmBaseRamEditor).RamEdPopup;
#2
You can create additional property in your TStringGrid
which will allow you to set editor popup menu:
您可以在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;
Since you are creating inplace replacement for default TStringGrid
class, approach with published property and setting EditorPopup
at design time may not work for you, but nothing stops you from setting EditorPopup
property in FormCreate
event, before user can start using string grid.
由于您正在创建默认TStringGrid类的inplace替换,因此在设计时使用已发布属性和设置EditorPopup的方法可能不适合您,但在用户可以开始使用字符串网格之前,没有什么能阻止您在FormCreate事件中设置EditorPopup属性。
#1
Use the owner of the TStringGrid
(the TfrmBaseRamEditor) as the reference and typecast it to the form to access the RamEdPopup
object:
使用TStringGrid的所有者(TfrmBaseRamEditor)作为引用并将其类型转换为表单以访问RamEdPopup对象:
TMaskEdit(Result).PopupMenu := TfrmBaseRamEditor(Self.Owner).RamEdPopup;
If you want to check the cast at runtime, use the as
intrinsic:
如果要在运行时检查强制转换,请使用as intrinsic:
TMaskEdit(Result).PopupMenu := (Self.Owner as TfrmBaseRamEditor).RamEdPopup;
#2
You can create additional property in your TStringGrid
which will allow you to set editor popup menu:
您可以在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;
Since you are creating inplace replacement for default TStringGrid
class, approach with published property and setting EditorPopup
at design time may not work for you, but nothing stops you from setting EditorPopup
property in FormCreate
event, before user can start using string grid.
由于您正在创建默认TStringGrid类的inplace替换,因此在设计时使用已发布属性和设置EditorPopup的方法可能不适合您,但在用户可以开始使用字符串网格之前,没有什么能阻止您在FormCreate事件中设置EditorPopup属性。