I'm creating dynamically ListBoxItems in a ListBox. Inside the ListboxItem I'm creating Layouts (3 of them) and inside those, Labels. Now I'm trying to search and find a specific label and change its text. I know how to do it in a way without using layouts with controls, but to make them look nicer I use Layouts. (ListBoxItem parenting->Layout parenting->Label) Check my code below that I use for searching the label and change the text.
var e,h : integer;
item : TListBoxItem;
Ctrl: TControl;
Lbl : TLabel absolute Ctrl;
layout : TLayout absolute Ctrl;
begin
item := ListBox1.ListItems[itemNum]; // specific listboxitem
for h:=0 to item.ControlsCount-1 do
begin
Ctrl:=item.Controls[h];
if Ctrl is TLayout then
begin
if layout.Name='lout3' then // i found the layout named "lout3" that i have 4 labels in
begin
for e:=0 to layout.ControlsCount-1 do // i check that the control count is correct(4)
begin
Ctrl:=layout.Controls[e]; // but at this line error occur "Argument out of range"
if Ctrl is TLabel then
begin
if Lbl.Name='qty1' then
begin
if ed_pos1.Text='' then
begin
Lbl.Text:=ed_pos1.TextPrompt;
end
else
begin
Lbl.Text:= ed_pos1.Text;
end;
end;
if Lbl.Name='qty2' then
begin
if ed_pos2.Text='' then
begin
Lbl.Text:=ed_pos2.TextPrompt;
end
else
begin
Lbl.Text:= ed_pos2.Text;
end;
end;
if Lbl.Name='qty3' then
begin
if ed_pos3.Text='' then
begin
Lbl.Text:=ed_pos3.TextPrompt;
end
else
begin
Lbl.Text:= ed_pos3.Text;
end;
end;
end;
end;
end;
end;
end;
end;
Somehow in that line layout.Controls don't have 4 entries that the controlCount says before. It goes in the loop for e=0 and the second time that enter the loop, e=1, it crashes with that error message. Any help will be appreciated.
First you are using absolute keyword which makes it really easy to shoot yourself in the foot. Even more so, when you have two variables (layout
and Lbl
) pointing to one (Ctrl
).
The problem in your code is that you set Ctrl
to a layout in the first loop, and then in the second loop you are reusing that variable again and assigning Ctrl:=layout.Controls[e]
which basically translates to Ctrl:=Ctrl.Controls[e]
because of the absolute
directive and your layout variable no longer holds the actual layout control in the second loop iteration.
You should use separate variable for second loop. I would suggest that you don't use absolute and simply directly use appropriate variable with typecasting.
You can even avoid typecasting, depending on properties you use. For instance layout
can easily be declared as TControl
and you just need to check its type to be sure you are accessing the layout, but you don't have to type cast it.
var e,h : integer;
item : TListBoxItem;
layout : TControl;
Lbl : TLabel;
begin
item := ListBox1.ListItems[itemNum];
for h:=0 to item.ControlsCount-1 do
begin
layout := item.Controls[h];
if layout is TLayout then
begin
if layout.Name='lout3' then
begin
for e:=0 to layout.ControlsCount-1 do
begin
if layout.Controls[e] is TLabel then
begin
Lbl := TLabel(layout.Controls[e]);
...