4

概述

我正在创建一个派生自 TCustomTreeView 的组件,我想添加一个在对象检查器中显示下拉列表 (paValueList?) 的属性。此列表必须基于附加到我的控件的另一个列表 (TStrings) 动态填充,例如它可以是来自 TComboBox、TListBox 的项目或来自 TStringList 等的字符串。

不过,我遇到了一些问题,我真的可以接受一些指导和建议。


代码布局

我缩短了代码以使其更易于阅读,但布局与我所拥有的基本相同。

我已经将我的组件包分成两个(同一个项目组),Package1包括组件代码(例如,我的组件从 TCustomTreeView 派生)并Package2包含注册过程和设计器单元(designide.dcp、DesignIntf​​、DesignEditors 等)。

Package2是我认为我需要添加我的属性编辑器的地方,该编辑器将用于我从 TCustomTreeView 中派生的组件Package1

包1

unit MyTreeViewUnit;

implementation

uses
  ...
  Classes,
  SysUtils;

type
  TMyTreeView = class(TCustomTreeView)
  private
    FSomeList: TStringList; // property editor should be filled using this list
    procedure SetSomeList(const Value: TStringList);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property SomeList: TStringList read FSomeList write SetSomeList;
  end;

  ....

包2

unit MyTreeViewPropUnit;

implementation

uses
  DesignIntf,
  DesignEditors,
  Classes;

type
  TMyTreeViewProperty = class(TStringProperty)
  public
    function GetAttributes: TPropertyAttributes; override;
    procedure GetValues(Proc: TGetStrProc); override;
    procedure Edit; override;
  end;

implementation

uses
  MyTreeViewUnit;  

function TMyTreeViewProperty.GetAttributes: TPropertyAttributes;
begin
  Result := [paValueList]; ?
end;

procedure TMyTreeViewProperty.GetValues(Proc: TGetStrProc);
begin
  inherited;
  // These cannot be added here!!
  // This list should be populated based on SomeList found in Package1 - MyTreeViewUnit.pas
  Proc('Item1');
  Proc('Item2');
end;

procedure TMyTreeViewProperty.Edit;
begin
  inherited;
  // ?
end;

unit MyCompsRegister;

interface

uses
  Classes;

procedure Register;

implementation

uses
  MyTreeViewUnit;
  MyTreeViewPropUnit;  

procedure Register;
begin
  RegisterComponents('MyTree', TMyTreeView);
  RegisterPropertyEditor(TypeInfo(String), TMyTreeView 'Test', TMyTreeView); // does not seem to add to object inspector for the component TMyTreeView
end;

end.

问题

  1. 第一个问题是我不知道我正在做的是否是正确的方法,我的组件已安装并且我可以毫无问题地使用它,尽管我的属性编辑器“测试”没有出现!

  2. 第二个问题是 GetValues 的填充方式。在线查看一些文章使我对迄今为止在填充属性编辑器等方面的内容有了基本的了解。尽管出于我的需要,无法以这种方式添加,在此示例中,我需要根据 GetValues 填充在第一个单元中分配给 SomeList 的字符串(正如我之前所说的 FSomeList 可以是 TListBox 例如)。

  3. 这与问题 2 有关如何让我的属性编辑器(在工作时)与我的树视图进行通信,以便我可以相应地填充它?

如果有人能给我一些指点,或者更好地指导我写一篇关于编写属性编辑器的好文章/指南,我将不胜感激。我在 Delphi.about、DelphiDabbler 等上读过的那些对我来说并不容易理解和遵循(我很容易感到困惑和陷入困境)。

非常感谢!

4

1 回答 1

6

这对于评论来说太长了,我想包含一些代码,所以这里有一个答案。首先,你的问题非常广泛。你需要停下来,这样你就可以提出中肯的问题。实际上,我开始回答您的第二个问题,并且在放弃之前很久就写了一些无法阅读的东西!

您应该从不需要属性编辑器的代码开始,即正常的运行时代码。属性编辑器不能成为自定义控件开发的核心,因为属性编辑器仅在设计时用于加快速度。如果要保持属性编辑器所做的更改,则它们将保存到对象检查器中以任何方式可见的已发布属性 (*1),而这些属性又会保存到 DFM 文件中。在创建表单时和设计时重新打开表单时(例如:如果您关闭 IDE 并重新打开它),相同的过程会在运行时恢复。由于一切都需要进入对象检查器,您可以跳过花哨的属性编辑器并让您的控制工作!

是什么促使我这么说:

procedure TMyTreeViewProperty.GetValues(Proc: TGetStrProc);
begin
  inherited;
  // These cannot be added here!!
  // This list should be populated based on SomeList found in Package1 - MyTreeViewUnit.pas
  Proc('Item1');
  Proc('Item2');
end;

该评论告诉我您还没有弄清楚如何将您的组件链接到不同的组件!这实际上是一个微不足道的步骤,一旦你开始工作,你就可以这样做:

procedure TMyTreeViewProperty.GetValues(Proc: TGetStrProc);
var s: string;
begin
  if Assigned(FLinkedCombo) then
    for s in FLinkedCombo.Items do
      Proc(s); // Beware, written in Browser!
end;

即使是那些微不足道的问题,如果没有该部分,对上述问题的回答将是不完整的,并且该部分包括关于TComponent.FreeNotification,TComponent.RemoveFreeNotificationTComponent.Notification

一旦您完成了大部分工作,您就可以开始使用您可能想要创建的任何属性编辑器。这项工作也将作为一个普通项目完成:您的目标是创建一个TMyComponentsEditor能够编辑您的属性或组件的简单表单(示例)。一旦你完成了这个工作,你就可以问:我如何让这个工作编辑器在 DesignTime 作为 Property 或 Component Editor 可用

*1) 当然,组件编辑器可以做涉及多个组件的花哨的东西;它还可以使用替代方法(即:不依赖简单的已发布属性)来持久化内容。

于 2012-12-23T19:11:39.483 回答