Step 5 - Custom Properties (Object Pascal)

From Appmethod Topics
Jump to: navigation, search

Go Up to Creating a FireMonkey Component (Object Pascal)


The component needs an additional property for the dialog's action verb, like "Save", to appear on the Do button. That verb is also combined with "Don't" on the Don't button. (More complex internationalization is beyond the scope of this topic.)

It would be simpler if you could rely on the presence of the button, and delegate to its Text to hold the verb. But the buttons are not there until the style is applied, and if the style is reapplied, the existing buttons are discarded. So the component needs to hold onto this string itself. Declare and implement a DoVerb property:

uses
  System.SysUtils, System.Classes, FMX.Types, FMX.Controls, System.UITypes;

type
  TDialogButtonPanel = class(TPanel)
  private
    FDoVerb: string;
    function GetDoVerb: string;
    procedure SetDoVerb(AString: string);
  protected
    function GetStyleObject: TControl; override;
    procedure ApplyStyle; override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property DoVerb: string read GetDoVerb write SetDoVerb;
    property Align default TAlignLayout.Bottom;
  end;

const
  DoButtonName = 'DoButton';
  DontButtonName = 'DontButton';
  CancelButtonName = 'CancelButton';
  mrDont = -mrOK;
constructor TDialogButtonPanel.Create(AOwner: TComponent);
begin
  inherited;
  Height := 46;
  Width := 300;
  Align := TAlignLayout.Bottom;
  DoVerb := 'Verb';
end;

function TDialogButtonPanel.GetDoVerb: string;
var
  Base: TFmxObject;
begin
  Base := FindStyleResource(DoButtonName);
  if Base is TTextControl then
    FDoVerb := TTextControl(Base).Text;
  Result := FDoVerb;
end;

procedure TDialogButtonPanel.SetDoVerb(AString: string);
var
  Base: TFmxObject;
resourcestring
  Dont = 'Don'#39't %s';
begin
  FDoVerb := AString;
  Base := FindStyleResource(DoButtonName);
  if Base is TTextControl then
    TTextControl(Base).Text := AString;
  Base := FindStyleResource(DontButtonName);
  if Base is TTextControl then
    TTextControl(Base).Text := Format(Dont, [AString]);
end;

procedure TDialogButtonPanel.ApplyStyle;
begin
  inherited;
  SetDoVerb(FDoVerb);
end;

The StyleName for each of the three buttons is declared as a constant, along with the "negative OK" modal result code for the Don't button. The FDoVerb field is added to the object to contain the verb string.

At run time, the access sequence goes like this:

  1. When the application is executed, all its forms are created, including the dialog box form containing the button panel. The panel is instantiated by its object line when loading from the .fmx. The constructor writes the default verb to the property, calling SetDoVerb. The field is set, and no buttons are found.
  2. Assigning the property values from the .fmx, SetDoVerb is called again with the string saved by the designer (for example, "Save"), changing the field.
  3. When the dialog box is opened, it is painted, and one of the preliminary steps of painting a control is to apply its style if necessary, which includes the first time the control is painted. This ends up calling ApplyStyle, which is overridden here to reapply the verb string from the field. It redundantly reassigns the field, but now that the buttons are present, it also sets the verb in the Do button, and combines "Don't" and the verb in the Don't button.
  4. Rendering the buttons does not go through GetDoVerb, because the buttons that comprise the style are rendered directly, and they already have the appropriate text, assigned by the setter method. The getter method is used primarily by the Form Designer and any run-time code that gets the panel's properties. For completeness, the method will attempt to update the field from the Do button, if it exists; but unless the button is manipulated directly (bypassing encapsulation), its text and the field should already be synchronized.


Previous

See Also