我需要在我的 PyQt 应用程序中显示一些图表,所以我写下了这些代码。它是有效的,但有时,绘制图表会花费大量时间,它会"冻结"主窗口。
我认为在另一个线程中执行此操作应该可以解决它。但是我该怎么做呢?或者,还有另一种方法可以在"非块"模式下绘制图表?
from PyQt4 import QtGui
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
class MplCanvas(FigureCanvas):
def __init__(self):
self.fig = Figure()
self.axes = self.fig.add_subplot(111)
# do something...
FigureCanvas.__init__(self, self.fig)
FigureCanvas.setSizePolicy(self, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
FigureCanvas.updateGeometry(self)
# do something...
def draw(self):
# do something...
您应该QThreads
您的Qt
应用程序中(以使框架工作为您完成所有艰苦的工作)
-
将耗时的工作放在工人类中(派生自
QObject
) -
在计算绘图的类中添加类似的东西
self.thread = QtCore.QThread(parent=self) self.worker = Worker(parent=None) self.worker.moveToThread(self.thread) self.thread.start()
并通过信号/插槽与您的工人沟通。 如果你直接调用它(如self.worker.do_slow_stuff()
),它将在你调用它的线程上运行,这将阻塞主事件循环,使接口冻结。
关于如何(和不)使用 QThread
进行线程处理的一个很好的解释(阅读两者。第一个现在描述默认行为)
像这样的简单用途的 Python 线程的基础知识非常简单。
您需要
import threading
然后,不要只调用 x.draw(),而是创建一个线程并按如下方式运行它:
draw_thread = threading.Thread(target=x.draw)
draw_thread.start()
这可能至少会让你完成 90%。您可以阅读文档以检测仍在运行的线程、等待线程等内容。但从本质上讲,这并不困难,如果 ti 只是简单的交互式图形,这甚至可能就足够了。
但请注意,如果 draw() 引用全局变量,则可能会出现竞争条件,从而使您的程序不可靠。这是编写具有良好耦合、干净接口且不引用可变全局变量的代码的另一个优势(除非使用锁定来保护这些资源)。