Looking at contents of your EWB Form
by Erick Engelke
August 27, 2024
Sometimes you would like to programatically access the various controls on your page.
For example, here is a page which generates a summary of the controls, their names, types, position (Left,Top), and contents. The list is generated when you press the clickme. That calls ListThem, a relatively simple function defined below.
procedure TForm1.ListThem;
var
i : integer;
c : TControl;
s : string;
xy : string;
begin
multilineedit1.Lines.Clear;
for i := 0 to controlCount - 1 do begin
c := controls[i];
// default to no data contents
s := '';
// read the data contents Caption or Text
if c is TButton then s := TButton(c).Caption;
if c is TLabel then s := TLabel(c).Caption;
if c is TEditComboBox then s := TEditComboBox(c).Text;
if c is TEdit then s := TEdit(c).Text;
// get the X,Y location of Left, Top for the control
xy := IntToStr( c.left ) + ', ' + IntToStr( c.top );
multilineedit1.Lines.Add('Control: ' + c.name + ' type: ' + c.classname + ' position: '+xy+ ' contents: ' + s);
end;
end;
procedure TForm1.Label1Click(Sender: TObject);
begin
listthem;
end;
Note that the visual controls are all descendants of TControl or descendants of TControl’s descendants, and every form (and every container, like TGroupBox and TPanel) have a list of _sub_controls you can iterate through.
The Pascal word is lets you compare to whether the class is of a specific type. So we handle each of the cases we expect with an is statement.
Note: even though TButton and TLabel both have Captions, we cannot share code to read the caption because the class is different, and internally they point to different member fields. We can only share code to read common things found through the same parent classes, like Top, Left, Name, ClassName, etc.
If you use a container class, like TBasicPanel, TGroupPanel, TScollPanel, TPain, TNotebook, etc. each will contain a list of controls. So to see all the _sub_controles you will typically use recursion.
procedure TForm1.ListThemRecursive( master: TControl );
var
i : integer;
c : TControl;
s : string;
xy : string;
begin
for i := 0 to master.controlCount - 1 do begin
c := master.controls[i];
// default to no data contents
s := '';
// read the data contents Caption or Text
if c is TButton then s := TButton(c).Caption;
if c is TLabel then s := TLabel(c).Caption;
if c is TEditComboBox then s := TEditComboBox(c).Text;
if c is TEdit then s := TEdit(c).Text;
// get the X,Y location of Left, Top for the control
xy := IntToStr( c.left ) + ', ' + IntToStr( c.top );
multilineedit1.Lines.Add('Parent: '+master.name + ' Control # '+inttostr(i)+': ' + c.name + ' type: ' + c.classname + ' position: '+xy+ ' contents: ' + s);
// recurse down
ListThemRecursive( c );
end;
// insert a blank line after each recusion with more than 0 sub controls
if i > 0 then multilineedit1.Lines.Add('');
end;
procedure TForm1.MultiLineEdit1Click(Sender: TObject);
begin
MultiLineEdit1.Lines.Clear;
ListThemRecursive( form1 );
end;
This is an example of recursive searching with two TBasicPanels (one is light red, the other pink), and sub controls
Notice that the EditCombox Box has a sub control of TListComboBox built-in. We didn’t add that, that’s part of EWB.
Using Tag field
All TControls have a Tag field which can hold a number. Sometimes you will enumerate all TControls, then make a determination on the Tag you set earlier, or on a KeyStroke event (ie. changed field).
Sample Uses: Validation
Suppose you want to ensure someone has filled out all the TEdits and other controls in a complex form to validate that there is something entered. Simply enumerate as above, then pop up an error message saying to enter all data.
You can even hover a TBalloonLabel slightly over the missing field, because you know the Left and Top positions relative to the owning container, and use that to guide the user to the right field.
I do that in several programs.