Search code examples
delphifiremonkey

Remove controls from a scrollbox


I am dynamicaly (at run time) adding controls into a TScrollBox using myScrollBox.AddObject

Now I need to remove all the controls I added to put new ones.

I tryed myScrollBox.Controls.Clear but after I call that function, any control I add are not showing up.

(Warning: I'm new to delphi and Firemonkey)

Update 1

Here is how I add my objects (this is just a test function)

procedure TMainForm.TaskDetailsAdd;
var
  btn1 : TButton;
  intI : Integer;
  count: Integer;

begin
  scbTaskVariables.BeginUpdate;

  count    := 0;
  for intI := 0 to 100 do
    begin
      btn1            := TButton.Create(self);
      btn1.Text       := 'Salut ' + IntToStr(intI);
      btn1.Parent     := scbTaskVariables;
      btn1.OnClick    := Button1Click;
      btn1.Tag        := intI * 10;
      btn1.Position.Y := intI * 50;
      btn1.Position.X := intI * 15;
      scbTaskVariables.AddObject(btn1);
      count := scbTaskVariables.ControlsCount;
    end;
  scbTaskVariables.EndUpdate;
end;

The funny thing is that if I place a break point on count := scbTaskVariables.ControlsCount I can see that ControlsCount goes from 0 to 1 for the first control and then it stays to 1 for the others.

Update 2

I submitted QC#125440.


Solution

  • I have added this as an Answer but as there are bugs in FMX it should be considered as a workaround at this stage.

    I spent some time on your problem about deleting your buttons, but also to tried to find out more about the bug. David was very quick to spot this and shows his experience.

    Two of my findings were that (1) the AddObect() does not appear to work with the buttons, for some reason, they are not being seen as "Objects" but as "Components". (2) Also I found that creating btn1 with the "scrollBox" as its owner helped to achieve an adequate result.

    I used 1 x TScrollbox, 2 x TButton and 4 x TLabel. The buttons left with their default name and the TScrollBox with Your default name. So you can just copy and paste. btn1 is made a private variable along with it's procedures.

    procedure TMainForm.TaskDetailsAdd;
    var
      intI : Integer;
    begin
      label1.Text := IntToStr(scbTaskVariables.ComponentCount);
          // Initial count = 1, Probably the scroll box.
    
    if scbTaskVariables.ComponentCount >1 then
      TaskDetailsDel; // Don't create Buttons with same Name if already exists.
    
    scbTaskVariables.BeginUpdate;
      for intI := 0 to 99 do
      begin
        Sleep(20); //Keeps the "Pressed Button" active to prove it is working
          btn1              := TButton.Create(scbTaskVariables);
          btn1.Parent       := scbTaskVariables;
          btn1.Position.Y   := intI * 50;
          btn1.Position.X   := intI * 15;
          btn1.Tag          := intI * 10;
          btn1.TabOrder     := 10 + intI;
          btn1.Name         := 'MyBtn' + IntToStr(intI);
          btn1.Text         := 'Salut ' + IntToStr(intI);
          btn1.OnClick      := Button1Click;
    
          if btn1.IsChild(scbTaskVariables) = true then
            Label2.Text := 'True'
          else               // All this, proves buttons not seen as children.
            Label2.Text := 'False';
    
          scbTaskVariables.AddObject(btn1);
                    // AddObject() taken out as button is not seen as "FmxObject"
      end;
    scbTaskVariables.EndUpdate;
    
      Label3.Text := IntToStr(scbTaskVariables.ComponentCount);
                    // Count now all created (includes ScrollBox).
      Label4.Text := IntToStr(scbTaskVariables.ControlsCount);
    end;
    

    The "TaskDetailsDel" procedure was was quite easy once I had determined that I was really dealing with "Components"

    procedure TMainForm.TaskDetailsDel;
    var
      intI : Integer;
      count: Integer;
    begin
      label1.Text := '';
      label2.Text := '';
      label3.Text := '';
      label4.Text := '';
    
      for intI := 0 to 99 do
        begin
          Sleep(20);   //Keeps the "Pressed Button" active to prove it is working
          btn1 := TButton(scbTaskVariables.FindComponent('MyBtn' + IntToStr(intI)));
            btn1.Parent := Nil;
              FreeAndNil(btn1);
        end;
      Count := scbTaskVariables.ComponentCount;
      Label1.Text := IntToStr(Count);
    end;
    

    Using the FindComponent line did the trick.

    Press F1 and type the links into the URL Box; I found these interesting, especially seeing how TButton is derived in the VCL and FMX.

    ms-help://embarcadero.rs_xe3/libraries/Vcl.StdCtrls.TButton.html
    ms-help://embarcadero.rs_xe3/libraries/FMX.Controls.TButton.html
    ms-help://embarcadero.rs_xe3/libraries/FMX.Types.TStyledControl.html
    ms-help://embarcadero.rs_xe3/rad/Objects,_Components,_and_Controls.html
    ms-help://embarcadero.rs_xe3/libraries/FMX.Types.TFmxObject.AddObject.html