How to untangle 2 components whose constructors depend on each other?

I am using this answer to force my own TPopupMenu

via the standard Cut / Copy / Paste context menu. The problem is I don't know how to lay out an OO structure to resolve this.

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 RamEdPopup

, defined in BaseRamEditor.dfm

. Note what is OnClick

referring to the method TfrmBaseRamEditor

:

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

      

So, a general overview:

  • The constructor TfrmBaseRamEditor

    depends on the overriddenTStringGrid

  • The constructor TStringGrid

    depends TPopupMenu

    on TfrmBaseRamEditor

    .
  • This one TPopupMenu

    points to methods TfrmBaseRamEditor

    .

How can I untangle this mess so TStringGrid

that the used in frmBaseRamEditor

is used TPopupMenu

?

+3


source to share


2 answers


Use the owner TStringGrid

(TfrmBaseRamEditor) as a reference and cast it into the form to access the object RamEdPopup

:

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

      



If you want to test the cast at runtime, use as

intrinsic:

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

      

+5


source


You can create an additional property in yours TStringGrid

that will allow you to set the editor popup menu:

  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 a default override for a class TStringGrid

, the published property approach and design- EditorPopup

time setting might not work for you, but there is nothing stopping you from setting the property EditorPopup

on an event FormCreate

before the user can start using the inline grid.

+5


source







All Articles