【问题标题】:Remove controls from a scrollbox从滚动框中删除控件
【发布时间】:2014-06-11 18:22:18
【问题描述】:

我正在动态地(在运行时)使用 myScrollBox.AddObject 将控件添加到 TScrollBox 中

现在我需要删除我添加的所有控件以放置新控件。

我尝试了 myScrollBox.Controls.Clear,但在调用该函数后,我添加的任何控件都没有显示出来。

(警告:我是 delphi 和 Firemonkey 的新手)

更新 1

这是我添加对象的方法(这只是一个测试功能)

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;

有趣的是,如果我在 count := scbTaskVariables.ControlsCount 上放置一个断点 我可以看到 ControlsCount 对于第一个控件从 0 变为 1,然后对于其他控件保持为 1。

更新 2

我提交了QC#125440

【问题讨论】:

    标签: delphi firemonkey


    【解决方案1】:

    AddObject 的倒数是RemoveObject。为您希望删除的每个子对象调用 ScrollBox.RemoveObject(aChildObject)

    另一种方法是设置子对象的Parent 属性。将其设置为ScrollBox 以添加它。将其设置为 nil 以将其删除。这可以与AddObjectRemoveObject 互换。无论哪种方式,你都可以做到。


    但是,当您尝试执行此操作时,正如您所说,如果您之前删除了控件,则尝试添加新控件会失败。这似乎是一个错误。请提交质控报告。

    我在 XE6 上测试过。

    【讨论】:

    • 我按照您的建议尝试了迭代,但我仍然遇到同样的问题。一旦我删除控件。有趣的是我添加了 100 个 TButton 但 ControlsCount 值为 2 ??当我单击它们时,A 可以看到滚动框中的 100 个按钮和单击事件(如果触发)。
    • 这可能是我一开始添加它们的方式。
    • 我编辑了这个问题,包括我如何首先创建控件。也许你会发现那里有问题。
    • 这是一个错误。您可以将代码与面板和其他容器一起使用。只是不滚动框。请提交质控报告。
    • 质检号是多少?
    【解决方案2】:

    我已将此添加为答案,但由于 FMX 中存在错误,现阶段应将其视为一种解决方法。

    我花了一些时间来解决您有关删除按钮的问题,但也试图找出有关该错误的更多信息。大卫很快就发现了这一点并展示了他的经验。

    我的两个发现是 (1) AddObect() 似乎不适用于按钮,由于某种原因,它们没有被视为“对象”,而是被视为“组件”。 (2) 我还发现,以“scrollBox”为所有者创建 btn1 有助于获得足够的结果。

    我使用了 1 个 TScrollbox、2 个 TButton 和 4 个 TLabel。按钮使用默认名称,TScrollBox 使用您的默认名称。所以你可以复制和粘贴。 btn1 与它的过程一起成为一个私有变量。

    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;
    

    一旦我确定我真的在处理“组件”,“TaskDetailsDel”过程就非常简单了

    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;
    

    使用 FindComponent 行成功了。

    按 F1 并在 URL 框中输入链接;我发现这些很有趣,尤其是看到 TButton 在 VCL 和 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
    

    【讨论】:

    • 它有效。即使它是一种解决方法,我也将您的答案标记为好。谢谢。
    • 供您参考,质检票已被回答并关闭。见qc.embarcadero.com/wc/qcmain.aspx?d=125440
    • 感谢您告诉我。看来我在很大程度上是在正确的轨道上。虽然我觉得奇怪的是,他谈论的是“内部内容对象”而没有更具体。
    【解决方案3】:

    尝试:

    myScrollBox.Content.DeleteChildren;
    

    【讨论】:

      【解决方案4】:

      TScrollBox 默认有 1 个类型为 TScrollContent 的组件,负责显示其他组件。因此,如果我们删除他,则不会显示任何内容。

      我在 TScrollBox 中创建了这个小函数来 RemoveAllComponents(期望 TScrollContent):

      procedure RemoveAllComponentsScrollBox(ScrollBox : TScrollBox);
      var i : integer; Obj : TFmxObject;
      begin
        for I := ScrollBox.ComponentCount-1 downto 0 do
        begin
          if ((ScrollBox.Components[i] is TFmxObject) and not (ScrollBox.Components[i] is TScrollContent)) then
          begin
            Obj:=TFmxObject(ScrollBox.Components[i]);
            Obj.Parent:=nil;
            FreeAndNil(Obj);
          end;
        end;
      end;
      

      这个方法可以通过递归来改进

      【讨论】:

        猜你喜欢
        • 2011-05-06
        • 1970-01-01
        • 2011-07-11
        • 2012-04-22
        • 2013-10-25
        • 1970-01-01
        • 2012-09-17
        • 2012-12-03
        相关资源
        最近更新 更多