如何防止与注册为组件的 TFrame 进行设计时交互

Posted

技术标签:

【中文标题】如何防止与注册为组件的 TFrame 进行设计时交互【英文标题】:How to prevent design-time interactions with TFrame registered as a component 【发布时间】:2015-08-16 12:58:00 【问题描述】:

我创建了一个想要注册为组件的新框架。我已经从this question 知道了 RegisterSprigType,所以它为我省去了一些麻烦。

RegisterSprigType 正确防止设计者选择、意外移动或删除框架内的控件,但只能直接选择。里面的控件仍然接受要删除的控件。

在我的情况下,我的框架内有面板。我可以在所述面板上放置一个按钮。如果我删除该按钮,则选择父级(恰好是面板),然后我可以删除面板。

我尝试从框架的 ControlStyle 中删除 csAcceptsControls。它确实阻止了控件直接放在框架上,但里面的面板仍然接受控件。

所以,我最终在“加载”过程中从我的框架中包含的所有控件中删除了 csAcceptsControls。

如果我的框架正在动态创建控件以响应属性更改,我想我还需要重写通知过程以从任何添加的控件中删除 csAcceptsControls。

所以,我的问题是,是否有更好的方法来实现相同的结果(防止设计者在注册为组件的框架内添加控件)。一个“寄存器”告诉设计者忽略作为容器的框架类及其子类?

如果这种方法已经是最优化的,我是否遗漏了什么?

这种方法有什么我应该注意的“陷阱”吗? (任何副作用?设计和运行时。)

【问题讨论】:

【参考方案1】:

我深入研究,但没有很好的解决方案来解决您的问题 因为所有方法都在 Frame 上下文而不是它的子组件中工作 比如 DesignWndProc、WM_NCHITTEST ...

但我有解决方案(不好)看下面,但我不知道它是否比你删除 csAcceptsControls 的解决方案更好。

您可以仅在设计时创建面板(透明)并仅从中删除 csAcceptsControls。在调整框架大小时,您可以设置此面板的宽度和高度以吃掉整个框架。 但是您必须使用 align alClient 将所有控件放在某个***面板(父级为 Frame)中,并且每个控件都将在其上。 然后你创建你的设计时间面板(父是框架),它将是你框架上的第二个***面板。 您只能在创建后将其置于前面一次。 此移除需要更改创建新控件的每个属性。

类似这样的结构 FramePanelTopLevelany other controlsDesignPanel:

object FrameTestDisableFrame: TFrameTestDisableFrame
  object PanelTopLevel: TPanel
    object Panel1: TPanel
      Left = 96
      Top = 56
      Width = 201
      Height = 105
      Caption = 'Panel1'
      TabOrder = 0
      object Button1: TButton
        Left = 48
        Top = 24
        Width = 75
        Height = 25
        Caption = 'Button1'
        TabOrder = 0
      end
    end
end

设计面板代码

TDesignPanel = class(TWinControl)
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
  public
    constructor Create(AOwner: TComponent); override;
  end;

实现

TDesignPanel

constructor TDesignPanel.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle:= ControlStyle - [csAcceptsControls];
  Color:= clBackground;
end;

procedure TDesignPanel.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle:= Params.ExStyle or WS_EX_TRANSPARENT;
end;

procedure TDesignPanel.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
  Message.Result:= 1;
end;

在你的框架中

private
    DesignPanel: TDesignPanel;

...

constructor TFrameTestDisableFrame.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle:= ControlStyle - [csAcceptsControls];
  if csDesigning in ComponentState then
    begin
      DesignPanel:= TDesignPanel.Create(Self);
      DesignPanel.Parent:= Self;
      DesignPanel.BringToFront;
    end;
end;



procedure TFrameTestDisableFrame.Resize;
begin
  inherited;
  DesignPanel.BringToFront;
  DesignPanel.SetBounds(0, 0, Width, Height);
end;

我对此进行了测试并且工作正常

提示

在我的情况下,我的框架内有面板。我可以在所述面板上放置一个按钮。如果我删除按钮,则父级被选中(恰好是面板),然后我可以删除面板。

在 delphi Seattle 中,当我删除此类按钮时,选择整个框架而不是父面板。

【讨论】:

以上是关于如何防止与注册为组件的 TFrame 进行设计时交互的主要内容,如果未能解决你的问题,请参考以下文章

在对象检查器上显示 TFrame 后代的附加属性

Delphi XE5,如何将包中定义的框架放入组件调色板

DAY87-BBS项目 数据库设计与简单登陆验证码

如何在 Delphi 的 TFrame 上模拟 OnDestroy 事件?

调整大小时防止 TPaintBox 闪烁

如何防止 Vue 组件上的默认标题设置?