Delphi Win32:加速动态创建的控件(父属性)

时间:2009-04-15 11:39:57

标签: delphi user-interface dynamic

我们有几个框架的GUI,可动态构建其内容。每个框架都会创建面板,标签,编辑,组合框等,以用作输入字段。这非常有效,我们还计划让每个框架在不同的线程中构建其内容。

但是有一个大问题:它很慢!创建控件不需要花时间,但设置Parent属性似乎非常耗时。

我已经尝试了几种方法来加快这个过程,但没有运气。我尝试过Enabled = False,Visible = False,DisableAlign,LockWindowUpdate,WM_SETREDRAW ......但似乎没有任何事情影响设置控件父级的耗时过程。

即使我们使用线程,这也需要时间,因为必须在Synchronize中调用VCL函数。

有没有其他方法可以加快创建和显示控件的速度?

亲切的问候, 马格努斯

编辑: GUI中没有触发数据感知组件或任何事件。我只是创建控件并显示它们。使用计时器我已经将控件parent(AControl.Parent:= AOwner)的赋值标识为耗时部分。

编辑2:如下面的答案所示,速度问题不是设置父级,而是设置控件的绘制。当我测试时间时,容器是可见的并且设置父级导致立即绘制控件。

编辑3:动态GUI的另一个耗时部分是将项目分配给组合框。 ComboBox.Items.Assign(DataItems),其中DataItems不超过三到六个项目。

感谢大家抽出时间帮助我!

8 个答案:

答案 0 :(得分:5)

不要尝试使用多个线程来创建控件,也不要尝试使用VCL。这无论如何都不会提高速度,但更重要的是与VCL完全禁止。

编辑你应该在StackOverflow上阅读处理VCL和多个线程的其他问题和答案,但简而言之:VCL不是线程安全的,所有对控件的访问都必须在主线程的上下文中完成。因此,当使用多个线程时,您必须在 Synchronize()调用中包装几乎所有内容,这实际上会序列化所有线程并进一步降低速度。

您最好的选择是重新构建UI,以便不需要一次创建它。只有在第一次显示所有帧时才按需创建所有帧。

编辑2:以下是一些测试代码,表明设置Parent属性不是真正的问题,但创建所有控件(包含所有需要的消息处理)可能是。

procedure TForm1.Button1Click(Sender: TObject);
var
  i, j, x, y: integer;
  Edit: TEdit;
  Ticks: LongWord;
begin
  Visible := FALSE;
  DestroyHandle;

  try
    for i := 1 to 20 do begin
      y := 20 + i * 25;
      for j := 1 to 10 do begin
        x := (j - 1) * 100;

        Edit := TEdit.Create(Self);
        Edit.SetBounds(x, y, 98, 23);
        Edit.Parent := Self;
      end;
    end;
  finally
    Ticks := timeGetTime;
    Visible := TRUE;
    Caption := IntToStr(timeGetTime - Ticks);
  end;
end;

在释放父窗体的句柄后,代码会动态创建200个 TEdit 控件。在我的系统上创建所有这些控件并设置它们的属性需要几十毫秒,但最后显示表单(将创建所有窗口)需要几百毫秒。由于这只能在主线程中完成,我怀疑使用多线程会对你有帮助。

答案 1 :(得分:2)

我不知道这是否可行,但您是否尝试将表单创建为.dfm文本格式,然后使用ObjectTextToBinary函数直接加载.dfm。这可能有效,也可能无效,值得研究。

答案 2 :(得分:2)

你在设置DisableAlign是什么?尝试对可以容纳子控件的每个控件(例如面板)执行DisableAlign。我之前看到过DisableAlign结果为动态构建的表单提供了巨大的加速。

编辑:再考虑一下,我的答案部分是推测性的。我不知道在控件树的根上设置DisableAlign的效果是否会流向它的子节点。我认为它没有,但也许它确实如此。我必须看一下VCL代码。 (关于加速的部分是正确的。)

答案 3 :(得分:2)

我前段时间发现了这个问题,并且通过简单地将控件托管在“临时”框架内(即未分配给表单的框架),显着缩短了创建时间。我相信每个控件与父表单(最后)进行通信的速度很慢,因为很多调用,例如SetBounds,SetVisible等。通过使用浮动框架,你可以完成并完成,然后将框架分配给表单你需要的。

答案 4 :(得分:1)

您可以将实际的数据检索卸载到后台线程,但UI内容必须在一个线程(主线程)中发生。因此,帧的实际设置将在同一个线程中进行。

您是否尝试过Profiler?可能是您的GUI过于连接,更新/连线会导致许多不必要的事件/副作用。使用分析器,您可以更深入地了解实际导致低性能的原因。例如,它可能表示您花了很多时间等待DB返回,或者可能是每个集都触发了触发另一个事件的事件。

答案 5 :(得分:1)

如果您使用数据软件控件,请确保在TDataSet上调用DisableControls。这也可能引起许多重新粉刺。

答案 6 :(得分:1)

另一个猜测:尝试使用Visible:= false创建容器(窗体,面板或框架)。然后将所有动态创建的控件附加到其上,然后设置Visible:= true

答案 7 :(得分:0)

只是一个疯狂的猜测:也许它有助于以反向层次顺序设置控件的父级,即首先设置最深嵌套控件的父级,然后设置其父级控件的父级,依此类推。 可能 会切断一些多余的刷新,因为Windows尚未“了解”您的控件。