Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/208.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在delphi中选择自定义控件中的子控件_Delphi_Design Time_Tcustomcontrol - Fatal编程技术网

如何在delphi中选择自定义控件中的子控件

如何在delphi中选择自定义控件中的子控件,delphi,design-time,tcustomcontrol,Delphi,Design Time,Tcustomcontrol,我正在尝试创建一个控件,它在设计时和运行时为自己创建3个标准TPanel。一切正常:控件完美地创建面板。但我遇到了一个问题:在设计时,我希望能够选择其中一个面板。 我希望重现TPageControl的标准行为:当用户单击屏幕上的TabSheet时,TabSheet将通过对象检查器进行编辑 下面附上我的控制代码: unit MyContainer; interface uses Windows, Messages, SysUtils, Classes, Graphics,

我正在尝试创建一个控件,它在设计时和运行时为自己创建3个标准TPanel。一切正常:控件完美地创建面板。但我遇到了一个问题:在设计时,我希望能够选择其中一个面板。 我希望重现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.
有没有人能告诉我一种方法来解决我的任务?
提前感谢。

这可以通过多种方式实现,具体取决于您的具体愿望。因为您的代码只显示了面板的创建,所以我假设您在能够实现自己的愿望之前需要非常基础的知识,但是对于一个新手组件生成器来说,基础知识可能有点难

首先:对于要在对象检查器中编辑的对象,它必须是组件或组件的已发布属性的一部分。现在,您的面板只是私有字段。因此,您可以尝试在属性中发布面板。或者,您可以为所有面板添加一个属性,这些面板将通过选定的索引属性进行区分

您还可以通过添加面板作为单独的组件来模拟页面控制组件。在这种情况下,您可能需要在上下文菜单中为新页面命令添加一个

一些注意事项:不需要该控件样式设置,除非组件通过设计器成为其他控件的父控件。而且,你的析构函数是多余的


然后试着问一个非常具体的组件编写问题。

这可以通过多种方式实现,具体取决于您的具体愿望。因为您的代码只显示了面板的创建,所以我假设您在能够实现自己的愿望之前需要非常基础的知识,但是对于一个新手组件生成器来说,基础知识可能有点难

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.
首先:对于要在对象检查器中编辑的对象,它必须是组件或组件的已发布属性的一部分。现在,您的面板只是私有字段。因此,您可以尝试在属性中发布面板。或者,您可以为所有面板添加一个属性,这些面板将通过选定的索引属性进行区分

您还可以通过添加面板作为单独的组件来模拟页面控制组件。在这种情况下,您可能需要在上下文菜单中为新页面命令添加一个

一些注意事项:不需要该控件样式设置,除非组件通过设计器成为其他控件的父控件。而且,你的析构函数是多余的


然后试着问一个非常具体的组件编写问题。

如果您想允许用户在设计时实际单击其中一个面板或任何其他子控件,主组件需要处理CM_DESIGNHITTEST消息,并为所需子控件内的任何鼠标坐标返回非零值。该消息在其lParam字段中包含鼠标坐标。您可以将该消息作为TWMMouse记录接收,其中有一个Pos字段,您可以使用SmallPointToPoint函数将其转换为TPoint。

如果您希望允许用户在设计时实际单击其中一个面板或任何其他子控件,主组件需要处理CM_DESIGNHITTEST消息,并为所需子控件内的任何鼠标坐标返回非零值。消息的lParam字段中包含鼠标坐标。您可以将消息作为TWMMouse记录接收,其中包含一个Pos字段,您可以使用SmallPointToPoint函数将其转换为TPoint。

我的问题有一个解决方案。
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.
我们需要使用TComponentEditor来获得在设计时创建面板的能力,类似于TPageControl。 感谢用户的帮助

下面的代码为我的组件注册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.

我的问题有一个解决办法。 我们需要使用TComponentEditor来获得在设计时创建面板的能力,类似于TPageControl。 感谢用户的帮助

下面的代码为我的组件注册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.

雷米·勒博,我试着处理这条信息,它真的很有效。现在,我可以在设计时单击子控件。但这并不能像TPageControl那样帮助我在设计时操作面板。但是感谢您为解决我的问题所做的努力,您希望用户具体操作什么?至于TPageControl,如果单击位于活动选项卡以外的任何选项卡上,它只会返回1,因此单击将指向基础Win32选项卡本身,因此它可以变为活动。我认为他可能希望与子面板进行相同的交互

在设计期间,可以单击TTabSheet而不是页面控件内的选项卡的方式。据我所知,之所以会发生这种情况,是因为TabSheet是以表单作为所有者创建的,而PageControl是父控件。因此,TabSheet看起来只是一个属于PageControl的控件,但实际上它本身就是一个设计时组件。如果这有任何意义的话:模糊的斯特克,是的,你理解我的权利!我只想重现当用户在设计时选择TabSheet而不是选项卡时PageControl的行为。顺便说一下,我尝试通过GetParentForm获取父窗体,并将其指定为面板所有者,将容器指定为面板的父窗体,但没有成功。因此,根据上面NGLN的建议,我将尝试实现我自己版本的PageControl的设计时弹出菜单,以便能够添加面板。Remy Lebeau,我只想强制我的控件在设计时创建一些面板,并提供一个通过对象检查器管理它们的选项:更改它们的属性、位置、删除它们。Remy Lebeau,我试着处理这个信息,它真的很有效。现在,我可以在设计时单击子控件。但这并不能像TPageControl那样帮助我在设计时操作面板。但是感谢您为解决我的问题所做的努力,您希望用户具体操作什么?至于TPageControl,如果单击位于除活动选项卡以外的任何选项卡上,它只会返回1,因此单击将指向基础Win32选项卡本身,这样它就可以变为活动。我认为他可能希望与子面板交互,就像在设计时可以单击TTabSheet而不是PageControl内的选项卡一样。据我所知,之所以会发生这种情况,是因为TabSheet是以表单作为所有者创建的,而PageControl是父控件。因此,TabSheet看起来只是一个属于PageControl的控件,但实际上它本身就是一个设计时组件。如果这有任何意义的话:模糊的斯特克,是的,你理解我的权利!我只想重现当用户在设计时选择TabSheet而不是选项卡时PageControl的行为。顺便说一下,我尝试通过GetParentForm获取父窗体,并将其指定为面板所有者,将容器指定为面板的父窗体,但没有成功。因此,根据上面NGLN的建议,我将尝试实现我自己版本的PageControl的设计时弹出菜单,以便能够添加面板。Remy Lebeau,我只想强制我的控件在设计时创建一些面板,并提供一个选项,通过对象检查器管理它们:更改它们的属性、位置、删除它们。NGLN,谢谢你描述一些事情。这非常有用,因为我不是德尔福的专业人士。为了达到上述目标,我决定创建一个按钮,该按钮在设计时可见,在运行时不可见,并通过单击按钮创建一个TPanel。我做到了,现在我可以点击这个按钮了,因为CM_DESIGNHITTEST消息已经处理完毕,Remy Lebeau注意到了。当点击被传递时,TPanel控件被创建,但我仍然不能在设计时选择它。我还试图为我的TPanel后代处理CM_DESIGNHITTEST,但它没有给我任何东西。NGLN,当我在你的帖子中写预览评论时,我记得,标准TPageControl有一个带有“New page”项的弹出菜单。我想这个菜单项中的代码可以为我的问题提供一些线索。昨天我研究了所有的TPageControl代码,但在设计阶段并没有与弹出菜单相关的内容。您知道,在哪里可以找到菜单项“New page”的源代码?对于这种上下文菜单命令,您必须创建一个组件编辑器,请参见答案中的“我的编辑”。但这涉及到对组件编写的大量知识的需要,这里的评论太多了这可能是一个伟大的单独的问题,如果不存在。NGLN,感谢链接。我会看看我能做些什么。NGLN,谢谢你描述一些事情。这非常有用,因为我不是德尔福的专业人士。为了达到上述目标,我决定创建一个按钮,该按钮在设计时可见,在运行时不可见,并通过单击按钮创建一个TPanel。我做到了,现在我可以点击这个按钮了,因为CM_DESIGNHITTEST消息已经处理完毕,Remy Lebeau注意到了。当点击被传递时,TPanel控件被创建,但我仍然不能在设计时选择它。我还试图为我的TPanel后代处理CM_DESIGNHITTEST,但它没有给我任何东西。NGLN,当我在你的帖子中写预览评论时,我记得,标准TPageControl有一个带有“New page”项的弹出菜单。我想这个菜单项中的代码可以为我的问题提供一些线索。昨天我研究了所有的TPageControl代码,但在设计阶段并没有与弹出菜单相关的内容。您知道,在哪里可以找到菜单项“New page”的源代码?对于这样的上下文菜单命令,您必须创建一个组件edito
r、 在答案中查看我的编辑。但这涉及到对组件编写的大量知识的需要,这里的评论太多了这可能是一个伟大的单独的问题,如果不存在。NGLN,感谢链接。我会看看我能做些什么。