How to select sub-control in my custom control in design-time in delphi

1.2k views Asked by At

I'm trying to create a control, which creates 3 standard TPanel onto itself in design-time and run-time. Everything is okay: control creates panels perfectly. But I struck with one problem: in design-time I want to have an ability to choose one of panels.
I wish to reproduce a standard behaviour of TPageControl: when user clicks on TabSheet on a screen, TabSheet becomes editable via object inspector.

Below attached a code of my control:

unit MyContainer;

interface

uses
  Windows,
  Messages,
  SysUtils,
  Classes,
  Graphics,
  Controls,
  Forms,
  StdCtrls,
  ExtCtrls,
  StrUtils,
  Dialogs;

type
  TMyContainer = class(TCustomControl)
  private
    FPanelA: TPanel;
    FPanelB: TPanel;
    FPanelC: TPanel;

  protected
    procedure Paint; override;

  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

  procedure register;

implementation

{ TMyContainer }

procedure Register;
begin
  RegisterComponents('MyComps', [TMyContainer]);
end;

constructor TMyContainer.Create(AOwner: TComponent);
begin
  Inherited Create(AOwner);

  Width := 200;
  Height := 200;
  ControlStyle := ControlStyle + [csAcceptsControls];

  FPanelA := TPanel.Create(Self);
  FPanelA.Parent := Self;
  FPanelA.Width := 100;
  FPanelA.Height := 60;
  FPanelA.Left := 10;
  FPanelA.Top := 10;

  FPanelB := TPanel.Create(Self);
  FPanelB.Parent := Self;
  FPanelB.Width := 100;
  FPanelB.Height := 60;
  FPanelB.Left := 10;
  FPanelB.Top := 80;

  FPanelC := TPanel.Create(Self);
  FPanelC.Parent := Self;
  FPanelC.Width := 100;
  FPanelC.Height := 60;
  FPanelC.Left := 10;
  FPanelC.Top := 160;
end;

destructor TMyContainer.Destroy;
begin
  FreeAndNil(FPanelA);
  FreeAndNil(FPanelB);
  FreeAndNil(FPanelC);

  Inherited Destroy;
end;

procedure TMyContainer.Paint;
begin
  Canvas.Brush.Color := clBlue;
  Canvas.FillRect(Canvas.ClipRect);
end;


end.

Is there someone who can show me a way to get a solution for my task?
Thanks in advance.

3

There are 3 answers

4
NGLN On BEST ANSWER

This can be implemented in many ways, depending on your specific wishes. Because your code does show nothing more than the creation of the panels, I assume you are in need of the very basics before you can even realize what your wishes exactly are, but then the basics may be a little hard for a novice component builder.

First of all: for something to be editable in the object inspector, it has to be a component or be (part of) a published property of a component. Right now your panels are just private fields. So you could try to publish your panels in properties. Or you could add one property for all panels which will be distinguished by a selected index property.

You could also mimic the page control component by adding panels as separate components. In that case you might need to add a component editor for a "New Page" command in its context menu.

Some notes: That control style setting is not needed, unless the component is ment to become parent of other controls by means of the designer. Also, your destructor is superfluous.

Then try asking a very specific component writing question.

5
Remy Lebeau On

If you want to allow the user to actual click on one of the panels at design-time (or any other child control, for that matter), your main component needs to handle the CM_DESIGNHITTEST message and return a non-zero value for any mouse coordinates that fall within the desired child control. The message contains the mouse coordinates in its lParam field (you can receive the message as a TWMMouse record, which has a Pos field that you can turn into a TPoint using the SmallPointToPoint() function).

0
Josef Švejk On

There is a solution for my question.
We need to use TComponentEditor to get an ability to create panels in design-time similar to TPageControl. Thanks to user NGLN for helpful link.

code below register TComponentEditor for my component (which was described in question).

unit MyEditor;

interface

uses
  Classes,
  SysUtils,
  TypInfo,
  StdCtrls,
  ComCtrls,
  ExtCtrls,
  Dialogs,

  ToolsAPI,
  DesignIntf,
  DesignEditors,
  VCLEditors,

  MyContainer; // our control

type
  {>>>>>>>>>>>>>>>>>>>>>>>>>}
  TMyContainerEditor = class(TComponentEditor)
  private
    procedure ExecuteVerb(Index: Integer); override;
    function GetVerbCount: Integer; override;
    function GetVerb(Index: Integer): string; override;
    procedure Edit; override;
  end;
  {<<<<<<<<<<<<<<<<<<<<<<<<<}

procedure Register;

implementation


{ TMyContainerEditor}

procedure Register;
begin
  RegisterComponentEditor(TMyContainer, TMyContainerEditor )
end;

procedure TMyContainerEditor.Edit;
begin
  ShowMessage('TMyContainerEditor editor');
end;

procedure TMyContainerEditor.ExecuteVerb(Index: Integer);
var
  Panel: TPanel;
begin
  Inherited ExecuteVerb(Index);
  case Index of
    0:  
      ShowMessage('Design editor');  
    1:                                    
    begin
      Panel:= TPanel.Create(Designer.Root);
      Panel.Parent := Designer.Root;
      Panel.Name := Designer.UniqueName('Panel');
      Designer.SelectComponent(Panel);
      Designer.Modified;
    end;
  end;
end;

function TMyContainerEditor.GetVerb(Index: Integer): string;
begin
  case Index of
    0: Result := 'Show info...';
    1: Result := 'Add page';
  end;
end;

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

end.