Delphi:浏览属性编辑器中的组件

时间:2015-09-11 14:26:25

标签: delphi properties editor components

当属性是任何类的简单组件时,IDE的属性编辑器能够以所有项目的形式下拉所有兼容组件的列表。

我想做一些等效的任务,但是根据属性的可接受组件类进行一些过滤;这些类的共同祖先只是 TComponent ,并且它们具有自定义接口。

目前我有一个工作属性编辑器,它使用 paValueList 属性和 GetValues 过程中的一些过滤,基于检查支持的接口,但它仅限于目前的形式: - (。

如何浏览IDE之类的所有表单?

2 个答案:

答案 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;