如果ListView中有许多从线程添加的记录,则窗口会冻结

时间:2011-03-16 07:40:52

标签: multithreading delphi listview delphi-xe

我的程序在分离的线程上执行“繁重”任务(搜索文件并查找签名)。每个任务都使用PostMessage来调用将记录添加到ListView的过程。

问题是当ListView(经常)显示很多记录时,我的窗口会冻结。似乎我的程序正在尖叫以请求Application.ProcessMessages。只有Progressbar仍在继续。操作完成后,一切恢复正常。

如果删除添加记录的操作,我的程序操作将顺利运行。

你有什么想法吗?

3 个答案:

答案 0 :(得分:8)

我们曾经达到了可以将多少邮件发布到邮件队列的限制。很可能你也达到了这个限制。

来自MSDN

  

发布的限额为10,000   每个消息队列的消息。这个限制   应该足够大。如果你的   应用程序超出限制,它   应该重新设计以避免   消耗了这么多系统资源。

来自The Best Synchronization is No Synchronization

  

PostMessage到主GUI线程的问题是你可以   “饱和”主GUI消息泵,   并干扰WM_TIMER和   WM_PAINT消息(这些消息是   仅在消息队列中调度   是空的,PostMessage意味着   队列可能永远不会是空的。在   此外,还有一个名义上的限制   输入队列中有10,000条消息;   之后,PostMessage将丢弃   消息并返回FALSE。在   另外,即使10,000限制是   不打,甚至几百条消息   可能意味着用户看到穷人   响应键盘和鼠标输入,   一种不可接受的情况。

答案 1 :(得分:2)

如果您使用多个项目,则可能需要更改程序的整体结构。

不是填写列表视图,而是尝试填充其他一些数据结构,然后让另一个线程使Windows更新并使用SendMessage。这样你的工作线程就不会停滞,你也不会淹没你的消息队列。另一方面,这需要在线程之间进行更多的同步。

另一种方法是对虚拟项使用某些控件,例如VirtualTreeview(可以配置为像列表视图一样)这样就可以填充后备数据结构和控件一旦项目滚动到视图中就会显示数据。因为即使有数百万件物品,一次只能看到少数物品,这可能会大大提高你的速度,因为现在填充控件只需要设置物品总数。

答案 2 :(得分:0)

您应该考虑使用虚拟网格控件,例如罗马mochalov的ExGridView或Mike Lishke非常流行的虚拟树视图(Delphi Gems)。当新内容到达时,只需设置一个标志,然后决定刷新屏幕的频率,并异步刷新,但不是每个新项目都要刷新一次。

无论如何,每200毫秒一次刷新将是大多数用户可以看到的。