当阻塞任务与 GUI 相关时,如何保持 PyQt GUI 响应?
Posted
技术标签:
【中文标题】当阻塞任务与 GUI 相关时,如何保持 PyQt GUI 响应?【英文标题】:How to keep PyQt GUI responsive when blocking tasks are GUI related? 【发布时间】:2015-11-23 15:48:14 【问题描述】:我正在编写一个应用程序,它将一堆 matplotlib
图形嵌入到 PyQt
GUI 中。这些数字的更新可能需要几秒钟,所以我想引入一个等待指示器,以便在绘制绘图时显示。我已将所有数据处理代码移到它自己的线程中,但似乎实际的绘图调用通常占处理时间的大部分。
我编写了一个等待指示器,它使用QTimer
实例在小部件上触发paintEvent
。当所有密集处理都可以推入另一个线程时,这工作得很好。问题是,由于Qt
的设计方式,这些构造matplotlib
绘图的调用无法移出主线程,因此阻止了等待指示器的更新,使其有点无用。
我在每个图更新后引入了一些对QCoreApplication.processEvents()
的调用,这稍微提高了性能。我还玩弄了猴子修补matplotlib.axes.Axes
的一堆方法以包括对QCoreApplication.processEvents()
的调用的想法,但我可以看到它变得混乱。这是我能做的最好的吗?有什么办法可以定时中断主线程,强制其处理新事件?
【问题讨论】:
我不知道解决这个问题的直接方法。我唯一能想到的就是减少你的绘图时间。似乎您尝试绘制的数据多于您的屏幕分辨率可以查看的数据。您可以在线程中对数据进行下采样,然后从主线程中绘图。可以在缩放时触发下采样,以便您始终将数据量与当前显示相匹配。我以前用 pyqtgraph 做过这个(我认为它比 matplotlib 稍快) 我怀疑您可能对某些数字是正确的。我会试试你的建议,看看能不能有所收获。但是,我认为这只是问题的一部分。数字的数量似乎比数据的大小更重要。 是的,matplotlib 不是很精简,尤其是如果您使用 imshow 之类的东西。我不确定你有多少个数字,但我已经用 pyqtgraph 中的下采样技巧完成了大约 20 个(所有 x 轴都链接在一起)。但我确信它高度依赖数据! 【参考方案1】:在线程中对QPixmap
进行实际绘图也应该有很大帮助。使用 QPainters drawPixmap()
方法绘制像素图非常快。只有在真正需要时(例如在缩放之后),您才需要重新创建像素图。与此同时,您只需要重用已经绘制的像素图。使用drawPixmap()
的实际paintEvents 几乎没有成本,而且您的GUI 将完全响应。
使用processEvent()
破坏代码不仅丑陋,而且会导致非常讨厌且难以调试的故障。例如。这可能会导致过早删除仍在使用但使用deleteLater()
计划删除的对象。
这个答案也可能有用:Python - matplotlib - PyQT: plot to QPixmap
我还没有使用 matplotlib。但是如果它直接使用 QWidgets 并且没有就不能使用它不会像你上面提到的那么容易。但是您可以在另一个由您的 GUI 启动的过程中进行绘图,该过程使用上面链接中的 matplotlib 并将像素图存储到磁盘,并且只要准备好新的像素图,您的 gui 就会加载。 QFileSystemWatcher
可能有助于避免轮询。
【讨论】:
以上是关于当阻塞任务与 GUI 相关时,如何保持 PyQt GUI 响应?的主要内容,如果未能解决你的问题,请参考以下文章