Eduardo Elias
Eduardo Elias

Reputation: 1760

How to change the default value for the Margins property?

Using the Delphi XE2 wizard to create a component, I have choose the TPanel to inherit from, and change defaults of some properties to fit my application.

My problem is to change the default of Margins:

  TControl = class(TComponent)
    ...
    property Margins: TMargins read FMargins write SetMargins;

Margins is a TMargin class declared with 4 properties that I need to redefine the defaults:

  TMargins = class(TPersistent)
  published
    property Left: TMarginSize index 0 read FLeft write SetMargin default 3;
    property Top: TMarginSize index 1 read FTop write SetMargin default 3;
    property Right: TMarginSize index 2 read FRight write SetMargin default 3;
    property Bottom: TMarginSize index 3 read FBottom write SetMargin default 3;

I can/will be setting on code the margins when the constructor of the component is called, however I have no idea how to redefine these defaults above in order to show up on the property editor.

Upvotes: 8

Views: 3268

Answers (1)

Sertac Akyuz
Sertac Akyuz

Reputation: 54812

You can declare your TMargins descendant with your own defaults to use in your panel

type
  TMyMargins = class(TMargins)
  protected
    class procedure InitDefaults(Margins: TMargins); override;
  published
    property Left default 10;
    property Top default 10;
    property Right default 10;
    property Bottom default 10;
  end;

class procedure TMyMargins.InitDefaults(Margins: TMargins);
begin
  with Margins do begin
    Left := 10;
    Right := 10;
    Top := 10;
    Bottom := 10;
  end;
end;


then when you create your panel, dismiss the existing one and use yours

  TMyPanel = class(TPanel)
  private
    procedure DoMarginChange(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TMyPanel.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Margins.Free;
  Margins := TMyMargins.Create(Self);
  Margins.OnChange := DoMarginChange;
end;

procedure TMyPanel.DoMarginChange(Sender: TObject);
begin
  // same as in TControl which is private
  RequestAlign;
end;

The margins will be stored in the dfm only when they differ from the default.



Although I don't know why the above works... The problem with the above code is, Margins property have a setter which only assigns to the margins (left, right..). The code never writes to the backing field, but it still works. The line

Margins := TMyMargins.Create(Self);

is effectively same as

TMyMargins.Create(Self);

which also works.

By 'works' I mean, it works. The margins, f.i., gets properly destroyed, not because of ownership etc.. (margins iş a TPersistent, not a component) but right when the ascendant TControl calls FMargins.Free.

Anyway, since I don't understand how it works, as a safer although hacky approach, I'd use this:

constructor TMyPanel.Create(AOwner: TComponent);
var
  Addr: NativeUInt;
begin
  inherited Create(AOwner);

  Addr := NativeUInt(@Margins);
  Margins.Free;
  PUINT_PTR(Addr)^ := NativeUInt(TMyMargins.Create(Self));
  Margins.OnChange := DoMarginChange;
end;

Upvotes: 8

Related Questions