Reputation: 1068
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.
Upvotes: 1
Views: 1324
Reputation: 1068
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.
Upvotes: 0
Reputation: 43669
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.
Upvotes: 3
Reputation: 597941
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).
Upvotes: 3