Creating a Component Editor and a Property Editor for FireMonkey Components

From RAD Studio
Jump to: navigation, search

Go Up to FireMonkey Components Guide


In this tutorial, you create a Property Editor and a Component Editor for a FireMonkey component.

The parent component for these editors is TClockLabel, the component that you create in the related tutorial Creating a Styled FireMonkey Component by Extending an Existing Component. This tutorial assumes that you already have created TClockLabel as a starting point.

TClockLabel Component:

TClockLabel4.png

A component editor is an IDE feature that you can invoke by double-clicking a component, or by right-clicking a component and selecting Show Editor on the context menu.

Invoking a Component Editor from a Custom Component:

ComponentEdContextMenu.png

Sample Component Editor shown as a Dialog:

SampleCompEditorDialog.png

A property editor is an IDE feature that you can provide as a way to edit a property (or a set of properties) in a separate dialog invoked from the Object Inspector.

To invoke a property editor from the Object Inspector, click the ellipsis [...] in the Value column for a given property.

Invoking a Property Editor from the Object Inspector:

PropEditorObjectInsp.png

In this tutorial, the component editor and the property editor display the same dialog box to edit the Format property of the TClockLabel component.

Step 1: Create a Design-Time Package

To create a property editor or component editor, you need to have a design-time package to hold these property editors.

  1. Right-click the ClockLabelProjectGroup in the Project Manager, and select Add New Project from the context menu:
    SelectProjectGroup.png
  2. Select File > New > Other > Delphi Projects.
    Then select Package in the New Items dialog box:
    PackageSelection.png
  3. Save this package as dclClockLabel.
  4. Select Project > Options > Description for dclClockLabel.
    Here you can select the type of package to create. Select Designtime only as the usage option:
    ProjctOptionsDescr.png

Step 2: Add a FireMonkey HD Form to Edit Properties

To edit a property of the TClockLabel component in a dialog box, now you need to add a Form that can edit the property.

  1. Make sure that the dclClockLabel project is active. If not, double-click dclClockLabelproject to make it the active project.
  2. Select File > New > Other > Delphi Files > Multi-Device Form.
  3. Confirm that this form is for FireMonkey by selecting Yes:
    ConfirmMessage.png
  4. Save the new form as ClockLabelDialog.
  5. In the Object Inspector, change the Name of the form to be ClockLabelDlg.
  6. Add and configure several FireMonkey controls, and update the look and feel of this dialog so that you have the following image:
    DesignerForClockLabel.png
    If you right-click the form and select View as Text from the context menu, the .FMX file code should be as follows:
 object ClockLabelDlg: TClockLabelDlg
  Left = 0
  Top = 0
  Caption = 'Designer for Clock Label'
 ClientHeight = 136
 ClientWidth = 383
  Visible = False
 StyleLookup = 'backgroundstyle'
 object ClockLabel1: TClockLabel
 Position.Point = '(104,96)'
    Width = 257.000000000000000000
    Height = 15.000000000000000000
 TabOrder = 0
    Text = '5/8/2012 1:50:42 PM'
    Format = 'c'
 end
 object EditFormat: TEdit
 Position.Point = '(16,52)'
    Width = 233.000000000000000000
    Height = 22.000000000000000000
 TabOrder = 1
 KeyboardType = Default
    Password = False
 end
 object Label1: TLabel
 Position.Point = '(16,32)'
    Width = 177.000000000000000000
    Height = 15.000000000000000000
 TabOrder = 2
    Text = 'DateTime Format for ClockLabel:'
 end
 object btnOK: TButton
 Position.Point = '(280,24)'
    Width = 80.000000000000000000
    Height = 22.000000000000000000
 TabOrder = 3
 ModalResult = 1
    Text = 'OK'
    Default = True
 end
 object btnCancel: TButton
 Position.Point = '(280,56)'
    Width = 80.000000000000000000
    Height = 22.000000000000000000
 TabOrder = 4
 ModalResult = 2
    Text = 'Cancel'
    Cancel = True
 end
 object btnPreview: TButton
 Position.Point = '(16,92)'
    Width = 80.000000000000000000
    Height = 22.000000000000000000
 TabOrder = 5
    Text = 'Preview'
 end
 end
7. Select the Edit box (EditFormat), and create an OnChange event handler for it as EditFormatChange:
  procedure TClockLabelDlg.EditFormatChange(Sender: TObject);
  begin
    ClockLabel1.Format := EditFormat.Text;
  end;
8. To compile this package, you need to add the following packages to the Requires section:
  • fmx
  • ClockLabel
  • designide
AddReferencecontextmenu.png
9. Compile the package.

Step 3: Create a Component editor to invoke a dialog box from the context menu

A component editor is a class that is inherited from TComponentEditor.

Create a new unit and a class in it as follows:

  1. Create a new unit and save it as ClockLabelEditors.pas.
  2. Add a reference to the following two units in the uses clause:
uses
  DesignEditors, DesignIntf;
3. Create a new class as a sub-class of TComponentEditor.
type
  TClockLabelComponentEditor = class(TComponentEditor)
  end;

Add a context menu

As discussed earlier, a component editor can display a context menu for the target component. When the user right-clicks the component, the GetVerbCount and GetVerb methods of the component editor are called to build the context menu.

You can override these methods to add commands (verbs) to the context menu as follows:

type
  TClockLabelComponentEditor = class(TComponentEditor)
  public
    function GetVerbCount: Integer; override;
    function GetVerb(Index: Integer): string; override;
  end;

function TClockLabelComponentEditor.GetVerbCount: Integer;
begin
  Result := 1;
end;

function TClockLabelComponentEditor.GetVerb(Index: Integer): string;
begin
  case Index of
    0: Result := '&Show Editor';
  else
    raise ENotImplemented.Create('TClockLabelEditor has only one verb (index = 0) supported.');
  end;
end;

Implement a command

When the command provided by GetVerb is selected in the Designer, the ExecuteVerb method is called. For every command you provide in the GetVerb method, you should implement an action in the ExecuteVerb method. You can access the component that is being edited using the Component property of the editor. To open a dialog defined earlier, now you need to add reference to the ClockLabelDIalog unit.

type
  TClockLabelComponentEditor = class(TComponentEditor)
  private
    procedure ShowDesigner;
  public
    procedure ExecuteVerb(Index: Integer); override;
  end;


procedure TClockLabelComponentEditor.ShowDesigner;
var
  DesignerForm: TClockLabelDlg;
begin
  DesignerForm := TClockLabelDlg.Create(nil);
  try
    // Set curent value to designer form
    DesignerForm.ClockLabel1.Format := (Component as TClockLabel).Format;
    DesignerForm.EditFormat.Text    := (Component as TClockLabel).Format;

    // Show ModalForm, and then take result
    if DesignerForm.ShowModal = mrOK then
      (Component as TClockLabel).Format := DesignerForm.ClockLabel1.Format;

    Designer.Modified;
  finally
    DesignerForm.Free;
  end;
end;

procedure TClockLabelComponentEditor.ExecuteVerb(Index: Integer);
begin
  case Index of
    0: ShowDesigner;
  else
    raise ENotImplemented.Create('TClockLabelEditor has only one verb (index = 0) supported.');
  end;
end;

Register the component editor in the IDE

To register a component editor to IDE, you need to call the RegisterComponentEditor routine from a register procedure, as follows:

procedure Register;
begin
  RegisterComponentEditor(TClockLabel, TClockLabelComponentEditor);
end;

After you build and install the package, your new component editor is ready to use.

Go back to TestClockLabelUnit, and invoke the context menu on TClockLabel. Now you should see the Show Editor command.

Step 4: Create a Property Editor to Invoke a Dialog Box from the Object Inspector

The steps to create a property editor are almost the same as the steps for creating a component editor.

A property editor is a sub-class of TPropertyEditor. In addition to the standard TPropertyEditor class, the designide unit defines several other useful classes. Because the Format property is a string value, this sample uses as a starting point TStringProperty, which is a sub-class of TPropertyEditor.

Set the attributes of the property editor

The property editor must provide information that the Object Inspector can use to determine the tools to display. For example, the Object Inspector needs to know whether the property has subproperties or can display a list of possible values.

To specify editor attributes, you need to override the property editor's GetAttributes method. GetAttributes is a method that returns a set of values of type TPropertyAttributes. In this tutorial, GetAttributes returns [paDialog] so that the IDE knows there is a dialog box available (see the list of available values in Specifying Editor Attributes).

To display a dialog box, the IDE calls the Edit method of the property editor. So the code should like this:

TClockLabelPropertyEditor = class(TStringProperty)
private
  procedure ShowDesigner;
public
  function GetAttributes: TPropertyAttributes; override;
  procedure Edit; override;
end;

{ TClockLabelPropertyEditor }

function TClockLabelPropertyEditor.GetAttributes: TPropertyAttributes;
begin
  Result := [paDialog];
end;

procedure TClockLabelPropertyEditor.Edit;
begin
  ShowDesigner;
end;

procedure TClockLabelPropertyEditor.ShowDesigner;
var
  DesignerForm: TClockLabelDlg;
begin
  DesignerForm :=TClockLabelDlg.Create(nil);
  try
    // Set curent value to designer form
    DesignerForm.ClockLabel1.Format := GetStrValue;
    DesignerForm.EditFormat.Text    := GetStrValue;

    // Show MordalForm, and then take result
    if DesignerForm.ShowModal = mrOK then
      SetStrValue(DesignerForm.ClockLabel1.Format);
  finally
    DesignerForm.Free;
  end;
end;

Finally, just as you registered a new Component Editor earlier, you need to register a new Property Editor by adding a call to RegisterPropertyEditor to the Register procedure:

  RegisterPropertyEditor(TypeInfo(string), TClockLabel, 'Format', TClockLabelPropertyEditor);

See Also