Component Development: Adding a context menu to your controls

Yet again, this post might “just” cover some basics, but as I always need to look this up when I haven’t developed a compnent in a while, I thought this might be helpful for everybody…

To add menu items to the context menu or the quick actions in the context menu gives your component an enhanced user-experience and should always be considered for implementation. You might simply offer dialog boxes that allow a guided configuration of your control or simply apply a certain set of settings. In this case, we will keep it very basic. For one, I want to show an About-dialog and I want to give the developer the real design-time experience, i.e. I want the developer to see how the component will look if executed at run-time.

context1

Above you see the two menu items: “About” and “Fetch Barcode”.

In order to provide menu items for you control, you need to provide a “component editor” (clearly keep it separated from a property editor). I quite often use the unit that registers the component to add the code for the component editor, but this might be put in a separate unit if the code becomes more complex and contains custom forms.

In order to derive your own component editor class from TComponentEditor, you have to use two units:

  • DesignEditors
  • DesignIntf
interface
uses uFlxVclBarcode, DesignEditors, DesignIntf, Dialogs, Classes;

Every component editor needs to implement three methods:

  • GetVerbCount: Integer : return the number of menu items that you will provide
  • GetVerb(Index:Integer):string : return the text for menu item Index
  • ExecuteVerb(Index: Integer) : the developer selected menu item Index , provide the code to be executed

The class declaration looks like this in my case:

type
  TFlxVclBarcodeComponentEditor=class(TComponentEditor)
    function GetVerbCount: Integer; override;
    function GetVerb(Index: Integer): string; override;
    procedure ExecuteVerb(Index: Integer); override;
  end;

Now we need to provide the implementation for the methods. There is no need to call inherited  for any of the methods that will be overwritten.

{ TFxlVclBarcodeComponentEditor }

function TFlxVclBarcodeComponentEditor.GetVerb(Index: Integer): string;
begin
  case Index of
    0: Result := '&About...';
    1: Result := 'Fetch Barcode';
  end;
end;

function TFlxVclBarcodeComponentEditor.GetVerbCount: Integer;
begin
  Result := 2;
end;

As we have a constant number of menu items I simply return the number. Yes, it is hard-coded. Of course, you might even pull the number from a webservice or a database when developing web controls or database controls. It is that flexible…

Just remember to provide texts and implementations for the number of menu items that you want to provide. If you forget to provide the code in ExecuteVerb, it will not hurt. If you do not provide a text, however, it might get you into trouble and might even crash the IDE.

I provide constant texts for every menu item. Again, it is an example. In a real-world product we would use variables to allow for easier lcoalization of the application.

procedure TFlxVclBarcodeComponentEditor.ExecuteVerb(Index: Integer);
begin
  case Index of
    0: MessageDlg( 'Flixments Barcode Component.' +
                   ' Copyright (c) 2016, Flixments, LLC.',
               mtInformation, [mbOK],0 );

    1: TFlxVclBarcode( Component ).Execute;
  end;
end;

In a more complex scenario the case-selection would call other methods with the implementation. This example is rather simple and thus I can provide the line in one code.

Note the usage of Component. Component returns the instance of the component that has been instantiated by the IDE. Neat, huh? Thus, we can also treat it like a component as if we would use it in our application. Remember that you need to cast it to the the component that you are implementing. The method we need to call in order to fetch the barcode is named “Execute” and thus we call TFlxVclBarcode( Component ).Execute; .

That’s it? No. One more thing… to register the component does not suffice as the component is not linked to its editor. You need to register the component editor as well for the IDE to pick it up. Just put the registration statement below the registration statement of the component itself:

procedure Register;
begin
  RegisterComponents('Flixments', [TFlxVclBarcode]);
  RegisterComponentEditor(TFlxVclBarcode, TFlxVclBarcodeComponentEditor);
end;

If you install your component now, the IDE will offer the context menu items and the actions in the object inspector.

Tags: ,

Partnerships




Top