如何在设计时获取窗体上所有组件的列表?

3
我需要在设计时获取窗体上所有组件的列表(不是控件,只是组件)。
这些组件也必须以24x24像素的图像形式显示在设计时的窗体上。
我可以使用如下代码:
procedure TForm2.GetComponentList(Memo1: TMemo)
var
  i: Integer;
begin
 for i := 0 to ComponentCount-1 do
   if (Components[i] is TComponent) and not (Components[i] is TControl) then
    Memo1.Lines.Add(Components[i].Name);
end;

但是在这里我将获得像TField等不可见的组件。

我只需要那些在IDE中以24x24位图形式显示在表单上的组件。

也许我可以使用Open Tools API?


1
你可以查看GExperts是如何实现的 - 请参见http://sourceforge.net/p/gexperts/code/HEAD/tree/trunk/Source/Experts/GX_HideNonVisualComps.pas。 - Uli Gerhardt
@Uli,除了GExperts可以使用和操作IDE中的UI元素('TContainer' WNDCLASS的实例),这与识别这些IDE UI元素在表单上所代表的TComponents不是同一回事(OP所要求的)。对于此,GExperts方法完全无用。 - Deltics
1个回答

5

作为其他组件的一部分创建的非可视化组件(例如,在 TDataSet 中的 TField)是包含组件的子级。在DFM中,这种关系是显而易见的 - 如果将其视为文本,则会看到字段组件是相应数据集对象的子级。

直接放置在表单上的非可视化组件(例如 TDataset 本身)是表单对象的子级:

object frmMain: TfrmMain
  ...
  object MyClientDataSet: TClientDataSet
    ...
    object MyClientDataSetID: TIntegerField
      FieldName = 'id'
    end
    object MyClientDataSetTitle: TStringField
      FieldName = 'title'
      Size = 255
    end
  end
  object MyDataSource: TDataSource
    DataSet = MyClientDataSet
    Left = 488
    Top = 120
  end
end

尽管非可视组件之间没有视觉上的父子关系,但它们仍然知道是否有父级组件。可以通过 TComponent 的 HasParent 属性进行访问。
然而,请注意,Form 不被认为是直接放置的非可视组件的父级(即 Form.Components 中的项)。
因此,如果一个非可视组件在表单上的 HasParent 为 FALSE(即 Form.Components 中的一项),则它是一个直接放置的组件,而不是其他组件的子级。
只需按以下方式修改您的 if 条件即可:
if (NOT (Components[i] is TControl)) and (NOT Components[i].HasParent) then
  Memo1.Lines.Add(Components[i].Name);

请注意,我已经删除了对于is TComponent的测试,因为对于一个窗体的Components属性中的项目,这个测试总是会返回TRUE

我猜问题是为什么问题中的代码不够用。 - David Heffernan
是的,我自己也意识到了...窗体始终拥有放置在其上的所有组件。我离答案很近了(几乎把手指紧紧地握在一起)......在DFM中,视觉或非视觉的关系没有区别,子组件都有父组件。然而有一个微妙的变化,这可以用来检测表单上的非视觉“根”组件。我已经相应地修改了答案,包括建议的代码更改以实现所需的结果。 - Deltics
现在好多了。 - David Heffernan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接