多线程环境下 PyQtGraph 绘画解决方案

2024-03-05 10:21:12 浏览数 (2)

在我们多线程编译并且使用PyQtGraph进行绘图时,我们需要确保所有的图形操作都在主线程中执行,主要是因为PyQtGraph是在主线程中创建的,并且不是线程安全的。下面我们将深入探讨在多线程环境下使用PyQtGraph绘图并做详细记录。

1、问题背景

在使用 PyQtGraph 绘图时,如果在主线程之外进行绘图操作,可能会出现绘图不生效或程序崩溃的问题。这是因为 PyQtGraph 的绘图操作需要在主线程中进行,否则可能会导致绘图操作与 GUI 界面更新操作冲突。

2、解决方案

为了解决这个问题,可以采用以下解决方案:

  1. 将绘图操作封装成一个函数,并将其放入一个队列中;
  2. 创建多个工作线程,并让每个工作线程从队列中获取绘图任务,然后在主线程中执行绘图操作;
  3. 通过信号和槽机制将工作线程和主线程连接起来,以便工作线程在完成绘图任务后通知主线程更新 GUI 界面。

以下是一个示例代码,演示了如何使用上述解决方案来在多线程环境下进行 PyQtGraph 绘图:

代码语言:javascript复制
from PyQt5 import QtCore, QtWidgets
import pyqtgraph as pg
import threading
import Queue
​
# 创建一个绘图对象
app = QtWidgets.QApplication([])
win = pg.GraphicsWindow(title="Basic plotting examples")
plot = win.addPlot(title="Simple plot", labels={'left': 'Y Axis', 'bottom': 'X Axis'})
curve = plot.plot(curve=np.random.normal(size=100))
​
# 定义绘图函数
def draw(data):
    curve.setData(data)
​
# 将绘图函数封装成一个类
class DrawingThread(threading.Thread):
    def __init__(self, queue):
        super(DrawingThread, self).__init__()
        self.queue = queue
​
    def run(self):
        while True:
            # 从队列中获取绘图任务
            data = self.queue.get()
​
            # 在主线程中执行绘图操作
            QtCore.QMetaObject.invokeMethod(curve, "setData", QtCore.Qt.QueuedConnection,
                                            QtCore.Q_ARG(object, data))
​
            # 通知主线程更新 GUI 界面
            QtCore.QMetaObject.invokeMethod(app, "processEvents", QtCore.Qt.QueuedConnection)
​
            # 标记任务完成
            self.queue.task_done()
​
# 创建一个队列来存储绘图任务
queue = Queue.Queue()
​
# 创建多个工作线程
num_worker_threads = 3
for i in range(num_worker_threads):
    thread = DrawingThread(queue)
    thread.daemon = True
    thread.start()
​
# 将绘图任务放入队列中
for i in range(100):
    queue.put(np.random.normal(size=100))
​
# 启动应用程序
app.exec_()

在这个示例中,我们创建了一个绘图对象 curve,并将其添加到 PyQtGraph 的绘图窗口中。然后,我们定义了一个绘图函数 draw(),这个函数将数据 data 绘制到 curve 上。

接下来,我们将绘图函数封装成一个类 DrawingThread。这个类继承自 threading.Thread,并重写了 run() 方法。在 run() 方法中,我们从队列中获取绘图任务,然后在主线程中执行绘图操作。

最后,我们创建了一个队列 queue 来存储绘图任务,并创建了多个工作线程来从队列中获取绘图任务并执行绘图操作。

在主线程中,我们通过信号和槽机制将工作线程和主线程连接起来,以便工作线程在完成绘图任务后通知主线程更新 GUI 界面。

通过这种方式,我们可以在多线程环境下进行 PyQtGraph 绘图,并且不会出现绘图不生效或程序崩溃的问题。

最重要的需要注意的是,虽然数据生成过程是在工作线程中进行的,但数据传输和绘图更新操作都是在主线程中执行的,以确保PyQtGraph的线程安全性。如果有更多问题可以留言探讨。

0 人点赞