3

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?

Craig
  • 1,874
  • 13
  • 41
DmitryB
  • 455
  • 1
  • 5
  • 18
  • 1
    You could check how [GExperts](http://www.gexperts.org/) do it - see http://sourceforge.net/p/gexperts/code/HEAD/tree/trunk/Source/Experts/GX_HideNonVisualComps.pas. – Uli Gerhardt Mar 12 '15 at 13:55
  • @Uli, except that GExperts is working with and manipulating the UI elements in the IDE (instances of the 'TContainer' WNDCLASS), which is not the same thing as identifying the **TComponents** that those IDE UI elements represent on the form (what the OP is asking for). The GExperts approach is entirely useless for that. – Deltics Mar 13 '15 at 01:54

1 Answers1

5

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.

Deltics
  • 22,162
  • 2
  • 42
  • 70
  • I guess the question then is why the code in the question isn't sufficient. – David Heffernan Mar 12 '15 at 19:09
  • Yes, I realised that myself... the form always owns all components placed on it. I was this close to the answer (holds fingers up almost pressed together)... there is no difference in the relationships in the DFM - for visual or non-visual, a child component has a parent. There is a subtle twist however, and this can be used to detect the non-visual 'root' components on a form. I have revised the answer accordingly, complete with suggested code change to achieve the desired outcome. – Deltics Mar 13 '15 at 01:31
  • That's a lot better now – David Heffernan Mar 13 '15 at 06:53