概述
我正在创建一个派生自TCustomTreeView的组件,我想添加一个属性,在Object Inspector中显示一个下拉列表(paValueList?)。此列表必须根据附加到我的控件的另一个列表(TStrings)动态填充,例如,它可以是来自TComboBox,TListBox的项目或来自TStringList等的字符串。
我遇到了一些问题,我真的可以提供一些指导和建议。
代码布局
我缩短了代码以使其更易于阅读,但布局基本上与我所拥有的相同。
我已将我的组件包分成两个(相同的项目组),Package1
包含组件代码(例如,我的组件派生自TCustomTreeView),Package2
包含注册过程和设计器单元(designide。 dcp,DesignIntf,DesignEditors等)。
Package2
我认为我需要添加我的属性编辑器,该编辑器将用于从Package1
中的TCustomTreeView派生的组件。
包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.
问题
第一个问题是我不知道我正在做什么是正确的方法,我的组件安装,我可以毫无问题地使用它,虽然我的属性编辑器'测试'没有显示!< / p>
第二个问题是GetValues的填充方式。在线查看一些文章让我对填写我的属性编辑器等方面的内容有了基本的了解。这不能以这种方式添加,虽然我需要的东西,在这个例子中我需要GetValues来填充基于在第一个单元中分配给SomeList的字符串(正如我在FSomeList之前所说的那样可以是TListBox)。
这与问题2有什么关系,如何让我的属性编辑器(工作时)与我的树视图进行通信,以便我可以相应地填充它?
如果有人能给我一些指示,或者更好的指导我写一篇关于编写房产编辑的好文章/指南,我将非常感激。我在Delphi.about,DelphiDabbler等上读过的内容对我来说并不容易理解和遵循(我很容易混淆并陷入困境)。
非常感谢!
答案 0 :(得分:6)
这对于评论来说太长了,我想要包含一些代码,所以这里有一个答案。首先,你的问题非常广泛。你需要把事情搞砸,这样你才能提出问题。我实际上已经开始回答你的 Number 2 问题了,我写了一些在放弃之前很难读的东西!
您应该从不需要属性编辑器的代码开始,即正常的运行时代码。属性编辑器不能集中来开发自定义控件,因为属性编辑器仅在设计时用于加速。如果属性编辑器所做的更改是持久的,那么它们将被保存到Object Inspector中以任何方式可见的已发布属性(* 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.RemoveFreeNotification
和{{ {1}}!
一旦你掌握了大部分工作,你就可以开始使用你想要创建的任何属性编辑器。这项工作也将作为一个普通项目完成:您的目标是创建一个能够编辑您的属性或组件的简单表单(例如TComponent.Notification
)。一旦你完成了这项工作,你就可以问:如何在DesignTime上将这个工作编辑器作为属性或组件编辑器。
* 1)当然,组件编辑器可以做涉及多个组件的花哨的东西;它也可以使用替代方法持久化(即:不依赖于简单的已发布属性)。