为什么在Firemonkey中在完成迭代时显示运行时创建控件?

时间:2017-03-19 21:39:22

标签: delphi runtime controls firemonkey

我在下面的代码中以runtine创建了100多个矩形;

var
  RectT: TRectangle;
  MyThread: TThread;
  Layout1: TLayout;
begin
  MyThread := TThread.CreateAnonymousThread(procedure()
  begin
        TThread.Synchronize(nil, procedure()
        var
            z, i: integer;
        begin
            z := 0;
            for i := 0 to 99 do
            begin
                 RectT := TRectangle.Create(Self);
                 RectT.Name := 'Rectangle' + IntToStr(i);
                 RectT.Align := TAlignLayout.Top;
                 RectT.Margins.Top := 6;
                 RectT.Position.Y := z;
                 RectT.Height := 20;
                 RectT.Parent := Layout1;
                 if (i mod 10) = 0 then Layout1.UpdateEffects;
                 inc(z, 20);
            end;
        end);
  end);
  MyThread.FreeOnTerminate := True;
  MyThread.Start;

端;

为什么在创建时不显示矩形,只在完成所有矩形的迭代时显示?

2 个答案:

答案 0 :(得分:2)

首先,你需要在一个线程中移动for循环并在Synchronize调用中创建矩形,就像Deltics所做的那样。区别在于您不需要调用Repaint,并且需要使用currentthread来传递调用以进行同步。

试试这个(在按钮的OnClick事件中):

procedure TForm4.Button1Click(Sender: TObject);
begin
  TThread.CreateAnonymousThread(procedure
  var
    I,z: Integer;
    Total: Integer;
  begin
    Total := 0;
    for I := 1 to 99 do
    begin
        TThread.Synchronize (TThread.CurrentThread,
          procedure
          var
            RectT: TRectangle;
          begin
            RectT := TRectangle.Create(Self);
            RectT.Name := 'Rectangle' + IntToStr(i);
            RectT.Align := TAlignLayout.Top;
            RectT.Margins.Top := 6;
            RectT.Position.Y := z;
            RectT.Height := 20;
            RectT.Parent := Layout1;
            Inc(z, 20);
          end);
    end;
  end).Start;
end;

答案 1 :(得分:1)

如果此代码在主线程上运行(由于您没有提及任何线程,这似乎是这种情况),那么FMX运行时具有可视化更新UI的第一个机会就是您的代码本身跑完了。

如果您希望UI更新以在添加矩形时显示矩形,那么您需要重新编写它以使用允许UI有机会定期重新绘制的方法。

更新

现在问题中的更新代码涉及一个帖子。但是,在您发布的代码中,您同步() 该线程中所有的工作。 同步 d代码在主线程中运行,因此同步所有工作的结果是删除线程的任何好处。

然而,你几乎就在那里。

对发布的代码进行小的更改,以便在线程中添加布局子对象,定期仅同步重新绘制布局对象本身,然后获得您正在寻找的结果:

var
  MyThread: TThread;
begin
  MyThread := TThread.CreateAnonymousThread
  (
    procedure()
    var
      z, i: integer;
      RectT: TRectangle;
    begin
      z := 0;
      for i := 0 to 999 do
      begin
        RectT := TRectangle.Create(Self);
        RectT.Name := 'Rectangle' + IntToStr(i);
        RectT.Align := TAlignLayout.Top;
        RectT.Margins.Top := 6;
        RectT.Position.Y := z;
        RectT.Height := 20;
        RectT.Parent := Layout1;

        TThread.Synchronize(nil, procedure()
                                 begin
                                   Layout1.Repaint;
                                 end);

        inc(z, 20);
      end;
    end
  );

  MyThread.FreeOnTerminate := True;
  MyThread.Start;
end;

我在 999 方法的演示中增加了子对象的数量,因为99不足以看到性能有任何明显变化。

正如所写,上面的代码也在添加了每个矩形之后重新绘制,但是这可以通过类似于发布的代码的方式轻松修改,以便仅在&#34之后重新绘制布局;批次"添加了矩形:

if (i mod 10) = 0 then 
  TThread.Synchronize(nil, procedure()
                           begin
                             Layout1.Repaint;
                           end);

这是一种简单的方法,解决了更新UI的直接问题,以显示使用这个非常简单的测试用例对该UI进行的一些后台更改的进度。在你的具体情况下,这是否真的是最合适的方法,你才能真正说出来。