select 如何在 delphi 的设计时在我的自定义控件中进行子控件
How to select sub-control in my custom control in design-time in delphi
我正在尝试创建一个控件,它在设计时和 运行 时在自身上创建 3 个标准 TPanel。一切正常:control 完美地创建了面板。但是我遇到了一个问题:在设计时我希望能够选择其中一个面板。
我希望重现 TPageControl 的标准行为:当用户单击屏幕上的 TabSheet 时,TabSheet 可通过对象检查器进行编辑。
下面附上我的控件代码:
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.
有人可以告诉我如何为我的任务找到解决方案吗?
提前致谢。
这可以通过多种方式实现,具体取决于您的具体愿望。因为您的代码只显示了面板的创建,所以我假设您需要非常基础的知识,然后才能真正了解您的愿望,但是对于新手组件构建者来说,基础知识可能有点难。
首先:要在对象检查器中编辑某些内容,它必须是一个组件或者是(的一部分)已发布的 属性 组件。现在你的面板只是私人领域。所以你可以尝试在属性中发布你的面板。或者您可以为所有面板添加一个 属性,这些面板将由选定的索引 属性.
区分
您还可以通过将面板添加为单独的组件来模仿页面控件组件。在这种情况下,您可能需要在其上下文菜单中为 "New Page" 命令添加 component editor。
一些注意事项:不需要控件样式设置,除非该组件通过设计器成为其他控件的父控件。另外,你的析构函数是多余的。
然后试着问一个非常具体的组件写作问题。
如果您希望允许用户在设计时实际点击其中一个面板(或任何其他子控件,就此而言),您的主要组件需要处理 CM_DESIGNHITTEST
消息,并且return 落在所需子控件内的任何鼠标坐标的非零值。该消息在其 lParam
字段中包含鼠标坐标(您可以将消息作为 TWMMouse
记录接收,其中有一个 Pos
字段,您可以将其转换为 TPoint
使用SmallPointToPoint()
函数)。
我的问题有解决方案。
我们需要使用 TComponentEditor 来获得在设计时创建面板的能力,类似于 TPageControl。
感谢用户 NGLN for helpful link.
下面的代码为我的组件注册了 TComponentEditor(在问题中有描述)。
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.
我正在尝试创建一个控件,它在设计时和 运行 时在自身上创建 3 个标准 TPanel。一切正常:control 完美地创建了面板。但是我遇到了一个问题:在设计时我希望能够选择其中一个面板。
我希望重现 TPageControl 的标准行为:当用户单击屏幕上的 TabSheet 时,TabSheet 可通过对象检查器进行编辑。
下面附上我的控件代码:
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.
有人可以告诉我如何为我的任务找到解决方案吗?
提前致谢。
这可以通过多种方式实现,具体取决于您的具体愿望。因为您的代码只显示了面板的创建,所以我假设您需要非常基础的知识,然后才能真正了解您的愿望,但是对于新手组件构建者来说,基础知识可能有点难。
首先:要在对象检查器中编辑某些内容,它必须是一个组件或者是(的一部分)已发布的 属性 组件。现在你的面板只是私人领域。所以你可以尝试在属性中发布你的面板。或者您可以为所有面板添加一个 属性,这些面板将由选定的索引 属性.
区分您还可以通过将面板添加为单独的组件来模仿页面控件组件。在这种情况下,您可能需要在其上下文菜单中为 "New Page" 命令添加 component editor。
一些注意事项:不需要控件样式设置,除非该组件通过设计器成为其他控件的父控件。另外,你的析构函数是多余的。
然后试着问一个非常具体的组件写作问题。
如果您希望允许用户在设计时实际点击其中一个面板(或任何其他子控件,就此而言),您的主要组件需要处理 CM_DESIGNHITTEST
消息,并且return 落在所需子控件内的任何鼠标坐标的非零值。该消息在其 lParam
字段中包含鼠标坐标(您可以将消息作为 TWMMouse
记录接收,其中有一个 Pos
字段,您可以将其转换为 TPoint
使用SmallPointToPoint()
函数)。
我的问题有解决方案。
我们需要使用 TComponentEditor 来获得在设计时创建面板的能力,类似于 TPageControl。
感谢用户 NGLN for helpful link.
下面的代码为我的组件注册了 TComponentEditor(在问题中有描述)。
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.