2016-02-29 80 views
1

我试图创建一个控件,它在设计时和运行时创建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. 

有没有谁可以告诉我一个办法让我的任务的解决方案?
在此先感谢。

回答

3

这可以根据您的具体愿望以多种方式实施。因为你的代码只显示面板的创建,所以我认为在你甚至可以意识到你的意愿之前,你需要非常基础的知识,但是对于新手组件构建者来说基础可能有点困难。首先:对于在对象检查器中可编辑的内容,它必须是组件的一部分,或者是组件的已发布属性(的一部分)。现在你的面板只是私人领域。所以你可以尝试在属性中发布你的面板。或者您可以为所有面板添加一个属性,这些属性将通过选定的索引属性进行区分。

您还可以通过将面板添加为单独的组件来模拟页面控件组件。在这种情况下,您可能需要在其上下文菜单中为“新页面”命令添加component editor

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

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

+0

NGLN,谢谢你介绍一些事情。这非常有用,因为我不是Delphi的专业人员。为了达到我指定的目标,我决定创建一个按钮,该按钮在设计时会显示,并且在运行时不可见,并会通过单击按钮创建一个TPanel。我做了它,现在我可以点击这个按钮,因为CM_DESIGNHITTEST消息处理,作为雷米Lebeau通知。当点击被传递时,TPanel控件被创建,但我仍然无法在设计时选择它。我也尝试为TPanel的后裔处理CM_DESIGNHITTEST,但它没有给我任何东西。 – Dima

+0

NGLN,虽然我写了我的预览评论到您的文章,我记得,标准TPageControl有一个PopupMenu项目'新页面'。我想这个菜单项的代码可以解释我的问题。昨天我研究了所有的TPageControl代码,但在设计时没有与PopupMenu相关的内容。你知道吗,我在哪里可以找到菜单项“新页面”的源代码? – Dima

+1

对于这样的上下文菜单命令,您必须创建一个组件编辑器,在答案中查看我的编辑。但是这涉及到大量关于组件写作的知识,对于这里的评论太多了。 ;-)(如果不存在,这可能是一个很好的单独问题)。 – NGLN

3

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

+0

雷米Lebeau,我试图处理这个消息,它是真的有用。现在我可以在设计时提供点击儿童控制。但是这并不能帮助我在设计阶段如何操作我的面板,以及TPageControl是如何操作的。但是,谢谢你为解决我的问题所做的努力)) – Dima

+0

你想让用户操作什么?至于'TPageControl',如果点击超出了活动标签以外的任何标签,它就会返回1,因此点击将直接指向底层的Win32标签本身,因此它可以变为活动状态。 –

+1

我想他可能想要与子面板进行交互,就像在设计时点击PageControl中的TTabSheet(而不是Tab)一样。据我所见,发生这种情况是因为TabSheet是以Form作为所有者创建的,但将PageControl作为Parent创建的。所以它看起来好像是TabSheet是一个属于PageControl的控件,但事实上它本身就是一个设计时组件。如果这有什么意义:) –

0

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