如何在单个PyQt GUI实例中多进程多个绘图

3

我有一个名为CrosshairPlotWidget的绘图对象。每个绘图对象都会生成一个线程来更新其数据,但这些线程仍然在同一个主GUI进程中。以下是我目前拥有的内容和示例:

enter image description here

1个主GUI进程,带2个线程

我希望可以在同一个GUI实例中分别运行这两个图形,但需要在不同的进程中运行。本质上,我试图将每个图形放入其自己的子进程中,以实现真正的并发,因为我的CPU受到了限制。通过将每个更新线程放在单独的进程中,它将绕过Python的全局解释器锁定。下面是所需目标的示意图:
1个主GUI进程,其中包含2个具有各自线程的子进程

我看过以下链接:

但是没有一个能够真正帮助到我。

我还发现了这个,它可以进行多进程处理,但不在同一个GUI窗口中。

from PyQt4 import QtCore, QtGui
import multiprocessing as mp
from threading import Thread
import pyqtgraph as pg
import numpy as np
import sys
import random
import time

class CrosshairPlotWidget(QtGui.QWidget):
    """Scrolling plot with crosshair"""

    def __init__(self, parent=None):
        super(CrosshairPlotWidget, self).__init__(parent)

        # Use for time.sleep (s)
        self.FREQUENCY = .025
        # Use for timer.timer (ms)
        self.TIMER_FREQUENCY = self.FREQUENCY * 1000

        self.LEFT_X = -10
        self.RIGHT_X = 0
        self.x_axis = np.arange(self.LEFT_X, self.RIGHT_X, self.FREQUENCY)
        self.buffer = int((abs(self.LEFT_X) + abs(self.RIGHT_X))/self.FREQUENCY)
        self.data = []

        self.crosshair_plot_widget = pg.PlotWidget()
        self.crosshair_plot_widget.setXRange(self.LEFT_X, self.RIGHT_X)
        self.crosshair_plot_widget.setLabel('left', 'Value')
        self.crosshair_plot_widget.setLabel('bottom', 'Time (s)')
        self.crosshair_color = (101,255,183)

        self.crosshair_plot = self.crosshair_plot_widget.plot()

        self.layout = QtGui.QGridLayout()
        self.layout.addWidget(self.crosshair_plot_widget)

        self.crosshair_plot_widget.plotItem.setAutoVisible(y=True)
        self.vertical_line = pg.InfiniteLine(angle=90)
        self.horizontal_line = pg.InfiniteLine(angle=0, movable=False)
        self.vertical_line.setPen(self.crosshair_color)
        self.horizontal_line.setPen(self.crosshair_color)
        self.crosshair_plot_widget.setAutoVisible(y=True)
        self.crosshair_plot_widget.addItem(self.vertical_line, ignoreBounds=True)
        self.crosshair_plot_widget.addItem(self.horizontal_line, ignoreBounds=True)

        self.crosshair_update = pg.SignalProxy(self.crosshair_plot_widget.scene().sigMouseMoved, rateLimit=60, slot=self.update_crosshair)

        self.update_data_thread = Thread(target=self.plot_updater, args=())
        self.update_data_thread.daemon = True
        self.update_data_thread.start()

    def plot_updater(self):
        """Updates data buffer with data value"""

        while True:
            self.data_point = random.randint(1,101)
            if len(self.data) >= self.buffer:
                del self.data[:1]
            self.data.append(float(self.data_point))
            self.crosshair_plot.setData(self.x_axis[len(self.x_axis) - len(self.data):], self.data)
            time.sleep(self.FREQUENCY)

    def update_crosshair(self, event):
        """Paint crosshair on mouse"""

        coordinates = event[0]  
        if self.crosshair_plot_widget.sceneBoundingRect().contains(coordinates):
            mouse_point = self.crosshair_plot_widget.plotItem.vb.mapSceneToView(coordinates)
            index = mouse_point.x()
            if index > self.LEFT_X and index <= self.RIGHT_X:
                self.crosshair_plot_widget.setTitle("<span style='font-size: 12pt'>x=%0.1f,   <span style='color: red'>y=%0.1f</span>" % (mouse_point.x(), mouse_point.y()))
            self.vertical_line.setPos(mouse_point.x())
            self.horizontal_line.setPos(mouse_point.y())

    def get_crosshair_plot_layout(self):
        return self.layout

if __name__ == '__main__':
    # Create main application window
    app = QtGui.QApplication([])
    app.setStyleSheet("""
        QWidget {
            background-color: #19232D;
            border: 0px solid #32414B;
            padding: 0px;
            color: #F0F0F0;
            selection-background-color: #1464A0;
            selection-color: #F0F0F0;
        }""")
    app.setStyle(QtGui.QStyleFactory.create("Cleanlooks"))
    mw = QtGui.QMainWindow()
    mw.setWindowTitle('Crosshair Plot')

    # Create and set widget layout
    # Main widget container
    cw = QtGui.QWidget()
    ml = QtGui.QGridLayout()
    cw.setLayout(ml)
    mw.setCentralWidget(cw)

    # Create crosshair plot
    crosshair_plot1 = CrosshairPlotWidget()
    crosshair_plot2 = CrosshairPlotWidget()

    ml.addLayout(crosshair_plot1.get_crosshair_plot_layout(),0,0,1,1)
    ml.addLayout(crosshair_plot2.get_crosshair_plot_layout(),0,1,1,1)
    mw.show()

    ## Start Qt event loop unless running in interactive mode or using pyside.
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

1个回答

3

图形用户界面(GUI)只能存在于属于主进程的主线程中,因此你所要求的是不可能实现的。就像在其他示例中所看到的,最接近你想要的是在另一个进程中产生实时数据的代码。

         Child Process 1               Child Process 2
        ┌----------------┐           ┌----------------┐  
        | ┌-----------┐  |           | ┌-----------┐  |
        | | Producer1 |  |           | | Producer2 |  |
        | └-----------┘  |           | └-----------┘  |
        └-------┬--------┘           └-------┬--------┘   
                |                            |
                └---------------┬------------┘
                                |
                       ┌--------┴--------┐ 
                       |  Main Thread    |
                       |  ┌-----------┐  | 
                       |  |    GUI    |  |
                       |  └-----------┘  | 
                       └-----------------┘
                          Main Process

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接