Delphi:在 属性 编辑器中浏览组件
Delphi: browsing components inside a property editor
当 属性 是任何 class 的简单组件时,IDE 的 属性 编辑器能够下拉列表中的所有兼容组件所有项目的表格。
我想做一些等效的任务,但要根据可接受的组件 classes 对 属性 进行一些过滤;这些 classes 的共同祖先只是 TComponent 并且它们具有自定义接口。
目前我有一个可用的 属性 编辑器,它使用 paValueList 属性和 GetValues 过程中的一些过滤,基于检查支持的接口,但仅限于当前形式:-(.
如何像IDE那样浏览所有表格?
I want to do some equivalent task, but with some filtering based on acceptable component classes for the property; these classes common ancestor is only TComponent and they have custom interfaces.
如果您只过滤 1 个接口,您应该更改有问题的 属性 以接受该接口类型而不是 TComponent
,然后更改默认的 属性 编辑器界面属性(TInterfaceProperty
)会自动为您过滤组件:
property MyProperty: IMyInterface read ... write ...;
Currently I have a working property editor that uses a paValueList attribute and some filtering in the GetValues procedure, based on checking the supported interfaces, but it is limited to the current form :-(.
How to browse all the forms like the IDE does?
要在自定义 属性 编辑器中手动过滤组件,您需要执行与默认组件 属性 编辑器 (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()
在这种情况下会 return TypeInfo(TComponent)
.
GetComponentNames()
(其实现在 IDE 中,在 VCL 源代码中不可用)枚举拥有正在编辑的组件的 Root(Form、DataModule 或 Frame)的组件,以及所有链接的 Root 对象,这些对象可以在编辑的 Root 的 uses
子句中指定的其他单元中访问。这是记录在案的行为:
DesignIntf.IDesigner60.GetComponentNames
Executes a callback for every component that can be assigned a property of a specified type.
Use GetComponentNames to call the procedure specified by the Proc parameter for every component that can be assigned a property that matches the TypeData parameter. For each component, Proc is called with its S parameter set to the name of the component. This parameter can be used to obtain a reference to the component by calling the GetComponent method.
Note: GetComponentNames calls Proc for components in units that are in the uses clause of the current root object's unit (Delphi) or included by that unit (C++), as well as the entity that is the value of Root.
因此,在您的 GetValues()
实施中,调用 Designer.GetComponentNames()
为 TComponent
指定 PTypeData
并让 IDE 枚举所有可用单位并为您提供带有每个组件名称的列表。然后你可以遍历该列表调用 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
中。它在枚举它们时实时过滤它们。
Remy 的解决方案非常适合我的需要。
不过我"simplified"有点过滤程序:
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;
当 属性 是任何 class 的简单组件时,IDE 的 属性 编辑器能够下拉列表中的所有兼容组件所有项目的表格。
我想做一些等效的任务,但要根据可接受的组件 classes 对 属性 进行一些过滤;这些 classes 的共同祖先只是 TComponent 并且它们具有自定义接口。
目前我有一个可用的 属性 编辑器,它使用 paValueList 属性和 GetValues 过程中的一些过滤,基于检查支持的接口,但仅限于当前形式:-(.
如何像IDE那样浏览所有表格?
I want to do some equivalent task, but with some filtering based on acceptable component classes for the property; these classes common ancestor is only TComponent and they have custom interfaces.
如果您只过滤 1 个接口,您应该更改有问题的 属性 以接受该接口类型而不是 TComponent
,然后更改默认的 属性 编辑器界面属性(TInterfaceProperty
)会自动为您过滤组件:
property MyProperty: IMyInterface read ... write ...;
Currently I have a working property editor that uses a paValueList attribute and some filtering in the GetValues procedure, based on checking the supported interfaces, but it is limited to the current form :-(.
How to browse all the forms like the IDE does?
要在自定义 属性 编辑器中手动过滤组件,您需要执行与默认组件 属性 编辑器 (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()
在这种情况下会 return TypeInfo(TComponent)
.
GetComponentNames()
(其实现在 IDE 中,在 VCL 源代码中不可用)枚举拥有正在编辑的组件的 Root(Form、DataModule 或 Frame)的组件,以及所有链接的 Root 对象,这些对象可以在编辑的 Root 的 uses
子句中指定的其他单元中访问。这是记录在案的行为:
DesignIntf.IDesigner60.GetComponentNames
Executes a callback for every component that can be assigned a property of a specified type.
Use GetComponentNames to call the procedure specified by the Proc parameter for every component that can be assigned a property that matches the TypeData parameter. For each component, Proc is called with its S parameter set to the name of the component. This parameter can be used to obtain a reference to the component by calling the GetComponent method.
Note: GetComponentNames calls Proc for components in units that are in the uses clause of the current root object's unit (Delphi) or included by that unit (C++), as well as the entity that is the value of Root.
因此,在您的 GetValues()
实施中,调用 Designer.GetComponentNames()
为 TComponent
指定 PTypeData
并让 IDE 枚举所有可用单位并为您提供带有每个组件名称的列表。然后你可以遍历该列表调用 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
中。它在枚举它们时实时过滤它们。
Remy 的解决方案非常适合我的需要。 不过我"simplified"有点过滤程序:
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;