【问题标题】:Is it wise to create composite controls?创建复合控件是否明智?
【发布时间】:2012-06-09 19:00:28
【问题描述】:

我有这个应用程序在许多地方重用了一种成语。有一个 TPanel,上面有一些标签和按钮。目的是允许用户选择一个日期范围。

“&Dates”标题是一个标签,“All Dates”部分是第二个标签。当用户单击“选择”按钮时,会弹出一个表单,向用户显示一对日期/时间控件和确定/取消按钮。如果用户在选择某些日期后点击 OK,第二个标签将变为“From mm/dd/yyyy To mm/dd/yyyy”。

创建一个封装这些控件的组件是否合理?我一直在查看组件编写者的各种资源,但它们似乎没有指出我正在考虑的问题,例如处理按钮的 onclick 事件。如果这是一个合理的尝试,我也很感激关于如何制作这种“复合控件”的描述的指针。

【问题讨论】:

  • 如果你不想写一个成熟的组件,你可以使用frames
  • +1。这是现代的替代方案。 (不过,您可能希望对其进行一些扩展;从技术上讲,它在这里不符合作为答案的条件,因为它只是一个离线链接,应该标记为“不是答案”。)您还可以多选不过,这些组件并使用 IDE 菜单中的Component->Create Component Template...。 (这是老式的方式,从 Delphi 1 或 2 开始就一直存在。)
  • 实际上,当我开始搜索短语“delphi 复合控件”时,我找到了 TFrame 替代方案,而且看起来确实可以解决问题。我希望它拥有的属性缺乏设计时支持,但它可能会解决问题。
  • 是的,框架也可以解决问题。但是,在设计时使用它们可能有点笨拙。对于较小的组件,例如您的示例中的组件,我通常会创建组件。但是,对于更复杂的复合安排,类似于表格,我通常使用框架。
  • 如果您喜欢编写执行绘图和鼠标事件的自定义控件,那么这是一个相当简单的控件。但是对于自定义控件的新手来说,学习如何编写控件将是一个很好的项目。这意味着没有TBitBtnTLabel,而只有TCustomControl 后代及其属性。按钮和文本将使用控件的重写 Paint 过程动态绘制。

标签: delphi components


【解决方案1】:

这是合理的,是的。

要创建这样的组件,只需从例如 TCustomPanel 派生一个新类,并将子组件作为字段添加到类中。

像这样:

TMyDatePicker = class(TCustomPanel)
protected
  FChooseButton: TButton;
  FClearButton: TButton;
public
  constructor Create(Owner: TComponent); override; 
end;

constructor TMyDatePicker.Create(Owner: TComponent)
begin
  // Inherited
  Inherited;

  // Create Choose Button
  FChooseButton := TButton.Create(Self);
  FChooseButton.Parent := Self;
  FChooseButton.Align := alRight;
  FChooseButton.Caption := 'Choose';

  // Create Clear Button
  FClearButton := TButton.Create(Self);
  FClearButton.Parent := Self;
  FClearButton.Align := alRight;
  FClearButton.Caption := 'Clear';
end;

要添加事件处理程序,只需将新的受保护过程添加到您的类。

例如:

procedure TMyDatePicker.HandleChooseButtonClick(Sender: TObject)
begin
  // Do whatever you want to do when the choose button is clicked
end;

然后将事件处理程序连接到选择按钮的 OnClick 事件(这应该在类的 Create 方法中完成):

FChooseButton.OnClick := HandleChooseButtonClick;

当然,还有比这更多的功能,例如微调按钮的对齐方式和添加图标。您还需要创建自己的事件,例如 OnDateSelected 或 OnDateModified。

但是,除此之外,我认为上面的例子至少应该让你继续前进。 :)

【讨论】:

  • 有些人建议不要在动态创建控件时设置 Parent。
  • @Altar 我想你可能会将它与在控件本身的构造函数中设置 Parent 的警告混淆了。应该避免这种情况,因为它破坏了 Delphi DFM 流系统的父分配逻辑。我认为我在这里的做法是正确的方法,让控件的所有者将其设置为 Parent 属性。
【解决方案2】:

是的,构建这样的组件绝对是明智的,因为它节省了大量的编码。

以下是半可视化创建它们的指南:How to Build Aggregate/Composite Components in Delphi

基本上,本文档中概述的过程是:

  1. 在 Delphi 的表单中设计组件的布局,将所有组件放置在 TPanel(或其后代)中。
  2. 选择并复制面板并将其粘贴到文本文件中。
  3. 将“=”的所有实例替换为“:=”,并添加一个分号 每行的结尾。
  4. 将所有 DFM“对象”声明行转换为适当的对象 构造函数代码,将所有可视控件的父级设置为 容器面板。
  5. 清除所有剩余代码。位图将需要放置在 资源文件。
  6. 将这个新的帕斯卡代码放在你的创建构造函数中 零件。在构造函数中,将对象部分分组到 适当的子组件创建者。

我认为文档的错误之处在于,例如,示例组件是从 TPanel 继承而来的,而对我来说,使用 TCustomPanel 并仅公开您想要的方法更有意义。

但它也解释了如何添加 OnClick 处理程序等。

这种方法的优点是您可以直观地完成 Panel 中组件的布局。

【讨论】:

  • 请注意,GExperts 有一个“组件到代码”向导,可以帮助您进行 = -> := 替换。
  • 很好,不知道。
【解决方案3】:

开发复合控件的一种非常实用的方法是使用TFrame 作为它的基础。

这样,您可以直观地设计控件,并使用事件或继承

您需要注意几件事,但总而言之,这比手动编写所有内容要容易得多(就像其他一些答案所建议的那样)。

注意事项(不是完整列表,但很接近):

  • don't forget the sprig
  • 在设计时(在 TFrame 中和将复合控件放在设计图面上时),标记为 Visible=True 的子控件仍然可见。解决此问题的两种方法:销毁这些控件,或将它们移动到不可见区域(顶部/左侧为负值或大于父级宽度/高度的值)
  • 将 TFrame 后代注册为组件,其中 TFrame 后代也是项目的一部分,有时会使 IDE 感到困惑。简单的解决方案:调用 TFrame 后代“TMyCustomControl”,从中派生“TMyControl”,并将“TMyControl”注册为组件。

另外,您不必从 TPanel 中移除斜角/边框和标题。

【讨论】:

    【解决方案4】:

    另一种方法是将组件组设为component template

    【讨论】:

    • @Ken 在第一个答案中指出了这一点,我确实看过它。我不喜欢它...基本上这看起来像是一种复制粘贴编程形式:它为所有控件克隆了所有分类的事件处理程序,例如,如果你使用它 n 次等等结果是错误的,你必须在n个地方修复它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-09
    • 1970-01-01
    • 2010-11-12
    • 2016-07-17
    • 2020-06-01
    • 2022-01-03
    • 2014-02-04
    相关资源
    最近更新 更多