Get a list of all controls in your Delphi FireMonkey (FMX) form .
Examples included a flat list and a hierarchical “tree” list
This is the FireMonkey (FMX) version of this topic.
For the VCL version go here
- First Level
A flat list showing all first level components on the form.
“first level only” means buttons on panels are excluded
- Full List
A complete list showing all components on the form (all levels)
Does not include components within frames
- Hierarchical “Tree” list
This includes components within frames
Filtering Out Junk
Doing this in FireMonkey is a bit more difficult than VCL due to the need to filter out lower level objects that you probably don’t care about. For example scroll bars on a memo.
To get the information that we need you need to work through two different lists
1) Children List
This is a list of direct (first level) children, so it excludes buttons on a panel
This also includes some junk that you will need to filter out (more on that later).
For example, in my first test an empty form contained a TRectangle with no name.
for i := 0 to self.ChildrenCount - 1 do memo1.Lines.Add (self.Children[i].name);
2) Components List
This is a list of all children, at all levels … flattened down into a single list
It will include lower level children such as a button on a panel
for i := 0 to self.ComponentCount- 1 do memo1.Lines.Add (self.Components[i].name);
To get a list of first level children, you need to get objects that appear in both lists. This will filter out the junk objects that you dont care about.
for i := 0 to self.ComponentCount - 1 do for j := 0 to self.ChildrenCount - 1 do if (self.Children[j]=self.components[i]) //same object then begin memo1.lines.Add (self.components[i].Name); break; // we found a match. no need to continue end;
This shows the key procedure to process all components recursively.
This works by getting objects that appears in both the Children list and the Components list. That logic filters out the junk objects mentioned above.
procedure TForm2.ProcessControlHierarchy ( aFMXObject : TFMXObject; aLevel : integer = 0 ); // process the control including its child objects // example use // ProcessControlHierarchy (self); var i : integer; j : integer; s : string; vFMXObject : TFMXObject; begin inc (aLevel); // do something with the control here // example 1) display control info memo1.lines.Add ( LeftPadString ('',(aLevel -1) * 6,' ') //indent based on level // + aLevel.ToString + ' ' + aFMXObject.name + ' (' + aFMXObject.ClassName +')' ); for i := 0 to aFMXObject.ChildrenCount - 1 do // process children begin // special considerations for frames if aFMXObject is TFrame then vFMXObject := aFMXObject else vFMXObject := self; // the form for j := 0 to vFMXObject.ComponentCount - 1 do begin if (aFMXObject.Children[i] = vFMXObject.Components[j]) then begin ProcessControlHierarchy ( aFMXObject.Children[i], aLevel ); break; // found match. no need to continue end; end; end; end;
Test for your control types
I have mainly focused on visual objects in this post so the hierarchy code does not include non visual components.
If you want to include non visual component like TDataSource you will need to modify the hieararchy code. This is because TDataSources appears in the Components list, but does not appear in the Children list.
I haven’t tested this for all types of controls, but it should be good enough for most situations.
See this related post for a VCL version of this post
Download full source code (Delphi 10.1) and pre-compiled demo
+1 this post
and here on BeginEnd
Thank You !
About The Author
The Usual Suspect
– Scott Hollows –
- Oracle and Delphi software developer.
- Australian Delphi User Group – Western Australia Chief Cat Herder
- Australian Delphi User Group – President