Delphi7, Create many controls with same properties - delphi

I am new to Delphi.
I would like to make an application in which will create a number of Buttons. Declaring an array of Tbuttons and create the buttons 1 by 1 is not very satisfying, because it is confusing and takes a lot of time. Using the Command For is also unsatisfying, because i won't be able to change some of button's properties, if needed, for example their position.
So i decided to declare a procedure in TForm1 Class, which creates the buttons based on what properties I send to the procedure. But for some reason it is not working (There aren't any syntax Errors):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm) //Declaring the procedure
procedure CreateButton(Button: TButton; L: Integer; T: Integer);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
B1, B2: TForm1; //Declaring controls
implementation
{$R *.dfm}
procedure TForm1.CreateButton(Button: TButton; L: Integer; T: Integer);
begin
Button:= TButton.Create(Self);
Button.Parent:= Self;
Button.Width:= 100; Button.Height:= 50;
Button.Left:= L; Button.Top:= T;
end;
procedure TForm1.FormCreate(Sender: TObject);
Var
Button1, Button2: TButton;
begin
B1.CreateButton(Button1, 100, 50); //Sending properties
B2.CreateButton(Button2, 200, 40); //Sending properties
end;
end.

AS: during the communication with topic starters answer grown too. The total outcome is like http://pastebin.ca/2426760
procedure TForm1.CreateButton(VAR Button: TButton; CONST L: Integer; CONST T: Integer);
That is of basics of Pascal language how to pass parameters to procedures/functions.
http://docwiki.embarcadero.com/RADStudio/XE4/en/Parameters_(Delphi)
Actually, I don't think there is any problem with the parameters
Button = nil, which means the values of "Button1" and "Button2" are not sent, however
http://pastebin.ca/2427238
Kudoes to Bill for spotting this. Using separate properties to position your controls is both inefficient and prone to copy-paste errors.
http://docwiki.embarcadero.com/Libraries/XE3/en/Vcl.Controls.TControl.SetBounds
http://docwiki.embarcadero.com/CodeExamples/XE3/en/BoundsRect_(Delphi)
Using the 2nd link:
procedure TForm1.CreateButton(out Button: TButton; const L: Integer; const T: Integer);
begin
Button:= TButton.Create(Self);
Button.Parent:= Self;
Button.SetBounds( L, T, 100, 50);
end;
Actually what do you do with pointers to newly created buttons ?
In your code you just loose them!
procedure TForm1.FormCreate(Sender: TObject);
Var
Button1, Button2: TButton;
begin
...
end;
In this your code those pointers would be just lost! If you do need those values - pass them outside of the procedure. If you do not - do not ask for them - http://en.wikipedia.org/wiki/YAGNI http://en.wikipedia.org/wiki/KISS_principle
Procedure TForm1.CreateButton(const L, T: Integer);
begin
With TButton.Create(Self) do begin
Parent := Self;
SetBounds( L, T, 100, 50);
Caption := 'Caption at ' + IntToStr(T);
Name := 'Name at ' + IntToStr(L);
End;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
B1.CreateButton( 100, 50); //Sending properties
B2.CreateButton( 200, 40); //Sending properties
end;
Now to those B1, B2...
You claim that you want 2 buttons on the form, but you code shows you try to make THREE FORMS and one button on the 2nd form and one button on the 3rd form. So what do you really want ??? And do you check that B1 and B2 forms were created befoe tryign to add buttons to them ?
Perhaps you really wanted
procedure TForm1.FormCreate(Sender: TObject);
begin
SELF.CreateButton( 100, 50); //Sending properties
SELF.CreateButton( 200, 40); //Sending properties
end;
Then to go with DRY principle and to keep all the variables in one place.
http://docwiki.embarcadero.com/Libraries/XE2/en/System.Types.TPoint
Procedure TForm1.CreateButtons(const a: array of TPoint);
Var p: TPoint;
Begin
for p in a do
CreateButton( p.x, p.y );
End;
type TPointDynArray = array of TPoint;
procedure TForm1.FormCreate(Sender: TObject);
begin
CreateButtons( TPointDynArray.Create(
Point( 100,50 ), Point(200, 40) ) );
end;
Kudos to Delphi array initialization
Later you can always add more coordinates to an array and keep it consistent.
Well, to bring down this to Delphi 7 abilities that would - somewhat redundantly - be coded like
const BtnCnt = 2;
BtnLocations : array [1..BtnCnt] of TSize = (
( cx: 100, cy: 50 ), ( cx: 200, cy: 40 )
);
Procedure TForm1.CreateButtons(const a: array of TSize);
Var i: integer;
Begin
for i := Low(a) to High(a) do
with a[i] do
CreateButton( cx, cy );
End;
procedure TForm1.FormCreate(Sender: TObject);
begin
CreateButtons( BtnLocations );
end;
But while Delphi 5 and Dephi 7 were great releases, they are very outdated. I definitely suggest you either upgradeing to Delphi XE or more recent, or side-stepping to CodeTyphon
TForm1 = class(TForm) //Declaring the procedure
procedure CreateButton(Button: TButton; L: Integer; T: Integer);
Declaring that one-purpose procedure in PUBLISHED section of the form class is also not a very good style. You'd better declare them in PRIVATE section. Adhering to "least visibility" would help you to make interdependencies controllable. Otherwise in a year your program would become a spaghetti mess, where you just cannot change anything without ruining everything else. I am workign on a project with 10+ years of history now and i see the consequences of "everything is public" very clear. It is a great pain!

Related

Set row color in TLMDGrid

I'm using LMD Innovative library in my inherited Delphi project, and in particular the TLMDGrid component.
I just want to set last row color (summary) different from the rest of the table.
I can set different colors for different columns in the designer, but (due to poor documentation) cannot find how to set color for a single row.
Thanks for help.
I don't use the LMD grids myself, so the following is based on their most recent trial download.
I wasn't sure whether you were asking about the TLMDGrid or the TLMDDbGrid so the
minimal demo below shows how to set the last row of both of them to a specific color. As you'll
see, it is just a question of setting up an OnGetCellColor event handler for each grid, and then
setting the value of the AColor variable by whatever criteria suit you.
The onGetCellColor event is passed the current column as well as the
row number of the grid cell which is about to be drawn, so this show give
you the possibility of coloring cells in the same row differently if you want.
I confess I'm not very happy with basing the test on the OnGetCellColor event of LMDDBGrid1
on the dataset's RecordCount, because not all dataset types return a meaningful value
(and for some, there can be big performance hit in getting its value. With a standard TDBGrid,
in its drawing events, you can rely on the dataset cursor being synced with the event calls (so that
any data values can be picked up from the current dataset row). I'm not sure yet about how
you would do that with the LMD grid - obviously the best place to ask about that would be LMD themselves.
Code:
unit LMDGridTestu;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
DB, DBClient, Grids, LMDGrid, LMDDBGrid;
type
TForm1 = class(TForm)
CDS1: TClientDataSet;
DataSource1: TDataSource;
CDS1ID: TIntegerField;
CDS1Name: TStringField;
LMDDBGrid1: TLMDDBGrid;
LMDGridIntegerColumn1: TLMDGridIntegerColumn;
LMDGridTextColumn1: TLMDGridTextColumn;
LMDGrid1: TLMDGrid;
NameCol: TLMDGridTextColumn;
IDCol: TLMDGridIntegerColumn;
procedure FormCreate(Sender: TObject);
procedure LMDDBGrid1GetCellColor(Sender: TObject; ACellState:
TLMDGridCellStates; ARowState: TLMDGridRowState; const AData: Variant;
AColumn: TLMDGridColumn; ARow: Integer; var AColor: TColor);
procedure LMDGrid1GetCellColor(Sender: TObject; ACellState: TLMDGridCellStates;
ARowState: TLMDGridRowState; const AData: Variant; AColumn: TLMDGridColumn;
ARow: Integer; var AColor: TColor);
public
end;
[...]
procedure TForm1.LMDDBGrid1GetCellColor(Sender: TObject; ACellState:
TLMDGridCellStates; ARowState: TLMDGridRowState; const AData: Variant;
AColumn: TLMDGridColumn; ARow: Integer; var AColor: TColor);
begin
if ARow = CDS1.Recordcount - 1 then
AColor := clYellow;
end;
procedure TForm1.LMDGrid1GetCellColor(Sender: TObject; ACellState:
TLMDGridCellStates; ARowState: TLMDGridRowState; const AData: Variant;
AColumn: TLMDGridColumn; ARow: Integer; var AColor: TColor);
begin
if ARow = LMDGrid1.DataRowCount - 1 then // Rows are numbered from zero
AColor := clYellow;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i : integer;
begin
CDS1.CreateDataSet;
CDS1.IndexFieldNames := 'ID';
for i := 1 to 12 do
CDS1.InsertRecord([i, StringOfChar(Chr((ord('a') + i -1)), 20)]);
CDS1.First;
LMDGrid1.DataRowCount := 10;
for i := 0 to LMDGrid1.DataRowCount - 1 do begin
LMDGrid1.Cells[IDCol.Position, i] := IntToStr(i);
LMDGrid1.Cells[NameCol.Position, i] := 'Name' + IntToStr(i);
end;
end;

For loop continue going after reaching goal. Delphi

This issue appears only with numbers, bigger, then 12 including.
Those two pictures captured in one time. How it is even possible?
For loop must go from 0 to 12-1=11, doesn't it?
Nevertheless, when I use while loop instead, it works fine.
Is it my fault or Delphi's?
P.S. Code down bellow.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids;
type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
Button1: TButton;
Edit1: TEdit;
Button2: TButton;
Label1: TLabel;
Button3: TButton;
Label2: TLabel;
Label3: TLabel;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure StringGrid1KeyPress(Sender: TObject; var Key: Char);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
n:Integer;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); //Button, that sets array length
var
i, index:Integer;
begin
val(Edit1.Text, n, index);
if(index<>0) then
begin
ShowMessage('Wrong number');
Edit1.Clear();
exit;
end;
StringGrid1.ColCount:=n;
for i:=0 to n-1 do
StringGrid1.Cells[i,0]:=IntToStr(i+1);
StringGrid1.SetFocus();
end;
procedure TForm1.Button2Click(Sender: TObject); //Main button
var
i, index:Integer;
a:array[0..10] of Real;
denom, sum:Real;
begin
i:=0;
sum:=0;
denom:=-1;
//that for loop from screenshot is here
for i:=0 to n-1 do
//while i<=(n-1) do
begin
Val(StringGrid1.cells[i,1], a[i], index);
if(index<>0) then
begin
ShowMessage('Wrong number with ' + IntToStr(i+1) + ' Id');
StringGrid1.Col:=i;
StringGrid1.Row:=1;
StringGrid1.SetFocus();
exit;
end;
a[i]:=a[i]/denom;
sum:=sum+a[i];
StringGrid1.Cells[i,2]:=FloatToStrF(a[i],ffFixed,5,3);
denom:=-denom*(i+2);
//Inc(i);
end;
Label2.Caption:=FloatToStrF(sum,ffFixed,5,3);
end;
//code down bellow just allow to go to another cell by pressing Enter
procedure TForm1.StringGrid1KeyPress(Sender: TObject; var Key: Char);
begin
if (Key=#13) and (StringGrid1.Col=(n-1)) then
Button2.SetFocus()
else if (Key=#13) and (StringGrid1.Col<>(n-1)) then
StringGrid1.Col:=StringGrid1.Col+1;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
Close();
end;
end.
As to answer your question of 'how is this even possible'...
In your screen, n is 12. As pointed out by Kermation, the highest index of a is 10, so when i is 11, unless you have range checking activated, when you write to a[11] (i=11) you will overwrite something else. This is in the local variable area so it might be i, for instance, or even internal variables you can't see like the limit used for the for loop, which is calculated at the start of the loop. Once you allow this to happen, pretty much anything is possible.
Of course the exact manifestation of the problem will very from one version of the compiler to another. In one version you might get away with it. in another you won't.
Array a size was smaller, then amount of cells.

How to create a combobox with two columns (one hidden) in Delphi 7?

How to create a TComboBox with two columns that has one of its columns hidden so that it can keep an id value along with the actual item in it? And then how to get to that id value programmatically?
There's no need for two columns here.
You can take advantage of the fact that TComboBox.Items (like many other things in Delphi, like TStringList, TMemo.Lines, and TListBox.Items) descends from TStrings, which has both the Strings and Objects properties. Objects stores anything the size of a TObject, which is a pointer.
This means you can store your integer value by simply typecasting it to a TObject when adding it, and typecasting it back to an Integer when retrieving it.
Something like this should work:
procedure TForm1.FormCreate(Snder: TObject);
var
i: Integer;
sItem: String;
begin
for i := 0 to 9 do
begin
sItem := Format('Item %d', [i]);
ComboBox1.Items.AddObject(sItem, TObject(i));
end;
end;
To retrieve the value:
procedure TForm1.ComboBox1Click(Sender: TObject);
var
Idx: Integer;
Value: Integer;
begin
Idx := ComboBox1.ItemIndex;
if Idx <> -1 then
begin
Value := Integer(ComboBox1.Items.Objects[Idx]);
// Do something with value you retrieved
end;
end;
Note that, since the Objects property is actually meant to store objects, this gives you a lot of flexibility. Here's an example (intentionally very trivial) of storing a customer's contact information in an associated object instance and displaying it in labels when an item from a listbox is selected.
unit Unit1;
interface
uses
Windows, Messages, Variants, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TCustomer=class
private
FContact: string;
FPhone: string;
public
constructor CreateCustomer(const AContact, APhone: string);
property Contact: string read FContact write FContact;
property Phone: string read FPhone write FPhone;
end;
TForm1 = class(TForm)
ListBox1: TListBox;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
lblContact: TLabel;
lblPhone: TLabel;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ListBox1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TCustomer }
constructor TCustomer.CreateCustomer(const AContact, APhone: string);
begin
inherited Create;
FContact := AContact;
FPhone := APhone;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var
i: Integer;
begin
for i := 0 to ListBox1.Items.Count - 1 do
ListBox1.Items.Objects[i].Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
lblContact.Caption := '';
lblPhone.Caption := '';
// Create some customers. Of course in the real world you'd load this
// from some persistent source instead of hard-coding them here.
ListBox1.Items.AddObject('N Company', TCustomer.CreateCustomer('Nancy', '555-3333'));
ListBox1.Items.AddObject('B Company', TCustomer.CreateCustomer('Brad', '555-1212'));
ListBox1.Items.AddObject('A Company', TCustomer.CreateCustomer('Angie', '555-2345'));
end;
procedure TForm1.ListBox1Click(Sender: TObject);
var
Cust: TCustomer;
begin
if ListBox1.ItemIndex <> -1 then
begin
Cust := TCustomer(ListBox1.Items.Objects[ListBox1.ItemIndex]);
lblContact.Caption := Cust.Contact;
lblPhone.Caption := Cust.Phone;
end;
end;
end.
ComboBox controls do not support columns, and you do not need a hidden column anyway to accomplish what you need.
The TComboBox.Items property is a TStrings descendant. It can hold both string values and associated user-defined data values together at the same time, but the user will only see the string values in the UI. Use the Items.AddObject() method to add string+ID values to the list, and then use the Items.Objects[] property to retrieve the ID values when needed.
Alternatively, you could just store your ID values in a separate array that has the same number of elements as the ComboBox and then use the ComboBox item indexes to access the array values. This is especially important if you need to store a value of -1, because that particular value is not retrievable from the Objects[] property of a TComboBox due to the way the getter method is implemented, like Rob said.

Taking a picture from a web-camera using WinAPI in Delphi 7

I have a challange: create a program which takes an image from a web-camera when a button is pressed. Additional condition: do not use third-party components (like DSPack), just the WinAPI. I wrote the following code.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls,ShellAPI;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Panel1: TPanel;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
const WM_CAP_START = WM_USER;
WM_CAP_STOP = WM_CAP_START + 68;
WM_CAP_DRIVER_CONNECT = WM_CAP_START + 10;
WM_CAP_DRIVER_DISCONNECT = WM_CAP_START + 11;
WM_CAP_SAVEDIB = WM_CAP_START + 25;
WM_CAP_GRAB_FRAME = WM_CAP_START + 60;
WM_CAP_SEQUENCE = WM_CAP_START + 62;
WM_CAP_FILE_SET_CAPTURE_FILEA = WM_CAP_START + 20;
function capCreateCaptureWindowA(lpszWindowName : PCHAR;
dwStyle : longint;
x : integer;
y : integer;
nWidth : integer;
nHeight : integer;
ParentWin : HWND;
nId : integer): HWND;
stdcall external 'AVICAP32.DLL';
var
Form1: TForm1;
implementation
{$R *.dfm}
var hWndC : THandle;
procedure TForm1.Button1Click(Sender: TObject);
begin
hWndC := capCreateCaptureWindowA('My Own Capture Window',
WS_CHILD or WS_VISIBLE ,
0,
0,
Panel1.Width,
Panel1.Height,
Panel1.Handle,
0);
if hWndC <> 0 then
SendMessage(hWndC, WM_CAP_DRIVER_CONNECT, 0, 0);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
hWndC := 0;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if hWndC <> 0 then
begin
SendMessage(hWndC, WM_CAP_DRIVER_DISCONNECT, 0, 0);
hWndC := 0;
end;
end;
end.
There are two buttons and a panel on the form. The program compiles successfully, and works well when launched the first time; however, at second and subsequent launches there appears a window which offers to select a device, but even after selecting it is not working. I would guess that after the first launch, the program is not returning the camera's driver to its original state.
Is this so? If it is, how can I correct it? If not, why does the program not work on second and other launches? Thanks for suggestions.
First of all, I wont be able to really help you with your current code, then again i think no one will so here is an alternative.
I understand you don't want to use a 3e party component but I think using AVICAP32.DLL is not a better option.
This page offers a great way to use webcams under windows, its very reliable and allows you to set any cam property. Its all opensource, easy to use and based on native windows DirectX libraries.
It has never failed me.
http://www.delphibasics.info/home/delphibasicsprojects/directxdelphiwebcamcaptureexample
Good luck and have fun,
Delphi rocks.

How to create an array of controls?

I have to create an array and place all controls there in order to access them.Here's a short example:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
const Test:Array[0..2] of TButton = (Button1,Button2,Button3);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
end.
Undeclarated idenitifier 'Button1' at the line where I declarated my array.But it's declarated three lines above.
Where's the problem,how to put all controls in an array?
EDIT:
Thank you for your answers,but I've got problems:
var TestA:TObjectList<TButton>;
var index:TComponent;
begin
TestA := TObjectList<TButton>.Create(false);
for index in Form7 do
if pos(index.name, 'Button') = 1 then
TestA.add(TButton(index));
TestA[0].Caption := 'Test'; //Exception out of range.
Ben's right. You can't set up a control array in the form designer. But if you have 110 images, for this specific case you can put them into a TImageList component and treat its collection of images as an array.
If you've got a bunch of more normal controls, like buttons, you'll have to create an array and load them into it in code. There are two ways to do this. The simple way, for small arrays at least, is Ben's answer. For large control sets, or ones that change frequently, (where your design is not finished, for example,) as long as you make sure to give them all serial names (Button1, Button2, Button3...), you can try something like this:
var
index: TComponent;
list: TObjectList;
begin
list := TObjectList.Create(false); //DO NOT take ownership
for index in frmMyForm do
if pos('Button', index.name) = 1 then
list.add(index);
//do more stuff once the list is built
end;
(Use a TObjectList<TComponent>, or something even more specific, if you're using D2009.) Build the list, based on the code above, then write a sorting function callback that will sort them based on name and use it to sort the list, and you've got your "array."
You may not be able to reference public properties of your form in an array constant like that. Try doing it in your form constructor/OnCreate event instead.
procedure TForm1.FormCreate(Sender: TObject);
begin
Test[0] := Button1;
Test[1] := Button2;
Test[2] := Button3;
end;
This function will iterate over all the controls on a specified container, like a particular TPanel or even the entire form, and populate a specified TObjectList with your TImage controls.
procedure TForm1.AddImageControlsToList(AParent: TWinControl; AList: TObjectList; Recursive: boolean);
var
Index: integer;
AChild: TControl;
begin
for Index := 0 to AParent.ControlCount - 1 do
begin
AChild := AParent.Controls[Index];
if AChild is TImage then // Or whatever test you want to use
AList.Add(AChild)
else if Recursive and (AChild is TWinControl) then
AddImageControlsToList(TWinControl(AChild), AList, True);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// Call like this or similar to get your list of images
// (assumes MyImageList is declared in Form)
MyImageList := TObjectList.Create(False);
AddImageControlsToList(Self, MyImageList, True);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
// Destroy the list
FreeAndNil(MyImageList);
end;
How about this?
procedure TForm1.FormCreate(Sender: TObject);
begin
for b := 1 to 110 do
Test[b] := FindComponent('Button' + IntToStr(b)) as TButton;
end;
You'll have to declare the array as a variable rather than a constant and it will have to go from 1 to 110 rather than 0 to 109 but that's no problem.
I use this all the time - it is simple and fast (despite Mr Wheeler's comment)- declare the maxbuttons as a constant
var
Form1: TForm1;
pbutton:array[1..maxbuttons] of ^tbutton;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
(* Exit *)
var k:integer;
begin
for k:=1 to maxbuttons do dispose(pbutton[k]);
close;
end;
procedure TForm1.FormActivate(Sender: TObject);
var k:integer;
begin
(*note the buttons must be Button1, Button2 etc in sequence or you need to
allocate them manually eg pbutton[1]^:=exitbtn etc *)
for k:=1 to maxbuttons do
begin
new(pbutton[k]);
pbutton[k]^:= tbutton(FindComponent('Button'+IntToStr(k)));
end;
end;
procedure TForm1.ButtonMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var k:integer;
b:boolean;
begin
b:=false;
k:=1;
while (k<= maxbuttons) and (not b) do
begin
if pbutton[k]^ = sender then (Note sender indicates which button has been clicked)
begin
{ found it so do something}
b:=true;
end;
k:=k+1;
end;
end;
Try this
var
TestA:TObjectList;
index:TComponent;
begin
TestA := TObjectList<TButton>.Create(false);
try
for index in Form7 do
if (pos is TButton) OR {or/and} (pos.tag and 8=8) then
TestA.add(TButton(index));
if TestA.Count>0 then //Fix:Exception out of range.
TestA[0].Caption := 'Test';
finally
TestA.Free;
end;
end;

Resources