How to get a list of all components on the Form at Design-Time?

DmitryB picture DmitryB · Mar 12, 2015 · Viewed 9.6k times · Source

I need to get a list of all components on the Form at Design-Time (not controls, just components).

The components must also be visible on the Form as a 24x24 image at Design-Time.

I could use code like this

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;

but here I will get invisible components like TField etc.

I need only components that the IDE show on the Form as a 24x24 bitmap.

May be I can use Open Tools API?

Answer

Deltics picture Deltics · Mar 12, 2015

Non-visual components created as part of other components (e.g. a TField within a TDataSet etc) are children of the containing component. This relationship is apparent in the DFM - if viewed as text you will see that the field components are children of the corresponding dataset object.

Non-visual components that are placed on the form directly (e.g. the TDataset's themselves) are children of the form object:

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

Even though there is no visual parent/child relationship between non-visual components, non-visual components never-the-less do know whether or not they have a parent.

This is accessible via the HasParent property of a TComponent.

Crucially however, a Form is not considered to be the parent of directly placed non-visual components.

Therefore, if HasParent is FALSE for a non-visual component on a form (an item in Form.Components) then it is a directly placed component, not a child of some other component.

Simply modify your if condition as follows:

if (NOT (Components[i] is TControl)) and (NOT Components[i].HasParent) then
  Memo1.Lines.Add(Components[i].Name);

Note that I have removed the test for is TComponent since this is always going to be TRUE for an item in the Components property of a form.