当属性是任何类的简单组件时,IDE的属性编辑器能够以所有项目的形式下拉所有兼容组件的列表。
我想做一些等效的任务,但是根据属性的可接受组件类进行一些过滤;这些类的共同祖先只是 TComponent ,并且它们具有自定义接口。
目前我有一个工作属性编辑器,它使用 paValueList 属性和 GetValues 过程中的一些过滤,基于检查支持的接口,但它仅限于目前的形式: - (。
如何浏览IDE之类的所有表单?
答案 0 :(得分:4)
我想做一些等效的任务,但是根据属性的可接受组件类进行一些过滤;这些类共同的祖先只是TComponent,它们有自定义接口。
如果只过滤1个接口,则应更改相关属性以接受该接口类型而不是TComponent
,然后接口属性的默认属性编辑器(TInterfaceProperty
)将自动过滤组件:
property MyProperty: IMyInterface read ... write ...;
目前我有一个工作属性编辑器,它使用paValueList属性和GetValues过程中的一些过滤,基于检查支持的接口,但它仅限于当前形式: - (。
如何浏览IDE之类的所有表单?
要在自定义属性编辑器中手动过滤组件,您需要执行与默认组件属性编辑器(TComponentProperty
)相同的操作以获取兼容组件,然后您可以根据需要进一步过滤它们
在内部,TComponentProperty.GetValues()
只需调用Designer.GetComponentNames()
,并将正在编辑的属性类型的PTypeData
传递给它:
procedure TComponentProperty.GetValues(Proc: TGetStrProc);
begin
Designer.GetComponentNames(GetTypeData(GetPropType), Proc);
end;
因此,如果您的财产接受TComponent
(因为这是您预期组件的唯一共同祖先):
property MyProperty: TComponent read ... write ...;
在这种情况下,GetPropType()
会返回TypeInfo(TComponent)
。
GetComponentNames()
(其实现在IDE中,在VCL源代码中不可用)枚举拥有正在编辑的组件的Root(Form,DataModule或Frame)的组件,以及所有链接的组件可以在已编辑的根uses
子句中指定的其他单位中访问的根对象。这是记录在案的行为:
DesignIntf.IDesigner60.GetComponentNames
为可以分配指定类型的属性的每个组件执行回调。
使用GetComponentNames为可以分配与TypeData参数匹配的属性的每个组件调用Proc参数指定的过程。对于每个组件,将调用Proc,并将其S参数设置为组件的名称。此参数可用于通过调用GetComponent方法获取对组件的引用。
注意:GetComponentNames以当前根对象单元(Delphi)的uses子句中包含的单元或由该单元(C ++)包含的单元中的组件调用Proc,以及作为值的实体Root
因此,在GetValues()
实施中,请Designer.GetComponentNames()
为PTypeData
指定TComponent
,并让IDE枚举所有可用单位,并为您提供每个组件的列表& #39;名称。然后,您可以循环遍历该列表,调用Designer.GetComponent()
以获取实际的TComponent
对象并查询它们以获取所需的接口:
procedure TMyComponentProperty.GetValues(Proc: TGetStrProc);
var
Names: TStringList;
I: Integer;
begin
Names := TStringList.Create;
try
Designer.GetComponentNames(GetTypeData(TypInfo(TComponent)), Names.Append);
for I := 0 to Names.Count-1 do
begin
if Supports(Designer.GetComponent(Names[I]), IMyInterface) then
Proc(Names[I]);
end;
finally
Names.Free;
end;
end;
实际上,这与默认的TInterfaceProperty.GetValues()
实现非常相似:
procedure TInterfaceProperty.ReceiveComponentNames(const S: string);
var
Temp: TComponent;
Intf: IInterface;
begin
Temp := Designer.GetComponent(S);
if Assigned(FGetValuesStrProc) and
Assigned(Temp) and
Supports(TObject(Temp), GetTypeData(GetPropType)^.Guid, Intf) then
FGetValuesStrProc(S);
end;
procedure TInterfaceProperty.GetValues(Proc: TGetStrProc);
begin
FGetValuesStrProc := Proc;
try
Designer.GetComponentNames(GetTypeData(TypeInfo(TComponent)), ReceiveComponentNames);
finally
FGetValuesStrProc := nil;
end;
end;
唯一的区别是TInterfaceProperty
不会浪费内存将名称收集到临时TStringList
中。它会在枚举时实时过滤它们。
答案 1 :(得分:0)
Remy的解决方案完全符合我的需求。 不过我已经“简化”了一下过滤程序:
procedure TMyComponentProperty.ReceiveComponentNames(const S: string);
var
Temp: TComponent;
Intf: IInterface;
begin
if Assigned(FGetValuesStrProc) then
begin
Temp := Designer.GetComponent(S);
if Assigned(Temp) then
if Temp.GetInterface(IMyInterface, IntF) then
FGetValuesStrProc(S);
// May add other interfaces checks here
end;
end;