2

平台:Delphi with VirtualTreeView SVN 5.1.0 & OmniThreadLibrary 3 SVN & Delphi XE2

本来以为是VirtualTreeView的问题。我需要每隔 1 秒或更短的时间将节点添加到 VST。但似乎迟早 CPU 速率会达到 50% 或更多,直到整个应用程序变得完全无响应。

  var FAbort:Boolean;
  .....

  procedure TrmMain.btnAddNodeClick(Sender: TObject);
    begin
      while not FAbort do
      begin
        VstMain.RootNodeCount:= VstMain.RootNodeCount + 1;
        Sleep(10);
        Application.ProcessMessages;
      end;
    end;

任何人都可以帮忙吗?蒂亚!

编辑:似乎问题来自OTL。使用上面的代码时,将应用程序的 CPU 最小化始终小于 1%,甚至将 10ms sleep 更改为 1ms。

但是,下面的代码将重现困扰我的问题。

procedure TForm1.btn5Click(Sender: TObject);
var
  I: Integer;
begin
  for I := 0 to 1 do
    CreateTask(
      procedure(const Task: IOmniTask)
      begin
        while not FAbort do
        begin
          Task.Comm.Send(1, 0);
          Sleep(10);
        end;
      end).OnMessage(
      procedure(const Task: IOmniTaskControl; const Msg: TOmniMessage)
      begin
        vst1.AddChild(nil);
      end).Run;
end;

PS:为了避免 OTL 默认的 1000 队列大小泛滥,我在每个线程中都有一个锁,等待添加节点在下一个 Task.Comm.Send 操作之前完成。

PPS:这里的 10ms 只是为了快速重现问题,而不是在实际情况下。所以不要费心问为什么?

好的,结论是:如果您需要定期更新该节点,则不要在单个节点上添加太多节点,节点越多更新它们的cpu时间越多。

4

2 回答 2

2

在我看来,当底层模型发生变化时,你不应该同步更新视图,尤其是每次都不要。

VirtualTreeView 是一个可视化控件。人类不需要实时看到树更新,每秒浪费超过 3 倍。所以不要这样做。

相反,更新您的模型(对象、类),设置通知标志,然后(从 TTimer)执行 VirtualStringTree.RootNodeCount 的异步 SINGLE 更新,最多每秒发生 3 次。(每 333 毫秒设置多个此更新标志会导致最短等待时间为 333 毫秒,直到它实际更新。)这是我的任意用户界面“比这更快,它只是闪烁和流失,没有任何用处”常量.

Delphi 自己的开发人员使用 VirtualTreeView 遇到了这个问题,我知道是因为我记录了所涉及的 QC 错误。如果您在 Delphi 2009 中执行了足够多的“OutputDebugString”消息,IDE 将变得无响应。为什么?因为他们做了你正在做的事。不要这样做。我并不是说用户点击应该导致屏幕刷新前等待 333 毫秒。我的意思是,某些连续生成树内容的进程应该只通知树的“视图控制器”每秒最多 3 次更改。

于 2013-01-11T19:51:35.097 回答
1

如果您使用 AddChild() 函数添加节点,则可能会比访问 RootNodeCount 属性更好。

例如:

procedure TMyForm.OnTimer( Sender: TObject );
var
  Node: PVirtualNode;
begin
  Node := MyTree.AddChild( nil );
  // fill in details with GetNodeData( Node );

end;

更好的是:使用计时器并尝试在每个时间间隔添加一些项目:

procedure TMyForm.OnTimer( Sender: TObject );
begin
  AddToList( ... );
end;

procedure TMyForm.OnTimer( Sender: TObject );
var
  Node: PVirtualNode;
  Item: <Some iterator>;
begin
  MyTree.BeginUpdate();
  try
    for Item in <somelist> do begin
      Node := MyTree.AddChild( nil );
      // fill in details with GetNodeData( Node );
    end;
  finally
    MyTree.EndUpdate();
  end; 
end;
于 2013-01-10T06:53:37.260 回答