Search code examples
androiddelphi

Change a Label text created dynamically in a layout in a ListBoxItem


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.


Solution

  • 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]);
                       ...