Не удается сделать отрисовку в процессе

Мне нужно параллельно рассчитывать данные для точек и рисовать их в двух процессах, но в одном графике. Попробовал одну коллекцию поместить в процесс, данные не рисуются, хотя считаются. Если запустить просто как обычную функцию 'print_func', то все рисуется.

import numpy as np
from PyQt5 import QtWidgets, QtChart
from PyQt5.QtCore import *
from multiprocessing import Process


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        self._chart_view = QtChart.QChartView()
        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        lay = QtWidgets.QVBoxLayout(central_widget)
        lay.addWidget(self._chart_view)
        self.adjust_axes()

    def print_func(self):
        scatterU = QtChart.QScatterSeries()
        scatterU.setColor(Qt.darkGreen)
        scatterU.setMarkerSize(10.0)
        U1 = np.random.random(50)
        U2 = np.random.random(50)
        for i in range(0, 50):
            scatterU.append(U1[i], U2[i])

        self.window()._chart_view.chart().addSeries(scatterU)

    def adjust_axes(self):
        D1 = np.random.random(50)
        D2 = np.random.random(50)
        chart = QtChart.QChart()
        scatterD = QtChart.QScatterSeries()
        scatterD.setColor(Qt.darkBlue)
        scatterD.setMarkerSize(10.0)
        for i in range(0, 50):
            scatterD.append(D1[i], D2[i])

        chart.addSeries(scatterD)
        chart.createDefaultAxes()
        self._chart_view.setChart(chart)

        procs = []
        proc = Process(target=self.print_func)
        procs.append(proc)
        proc.start()
        procs[0].join()
        #self.print_func()



if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

Ответы (1 шт):

Автор решения: S. Nick

Вы не можете взаимодействовать с виджетами в дополнительных потоках.

В дополнительных потоках вы оперируете только с какими-то данными,
затем посредством сигналов эти данные передаются в основной поток
и уже в основном потоке вставляете эти данные в виджеты.

Возможный вариант решения выглядит примерно так:

import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets, QtChart 
from PyQt5.QtCore import *


class Thread(QtCore.QThread):
    threadStart = QtCore.pyqtSignal(int)
    threadData = QtCore.pyqtSignal(int, object, object)
    threadFinish = QtCore.pyqtSignal(int)

    def __init__(self, id): 
        super().__init__() 
        self.id = id

    def run(self):
        self.threadStart.emit(self.id)
        self.msleep(100) 
        while True:
            U1 = np.random.random(50)
            U2 = np.random.random(50)
            for i in range(0, 50):
                self.threadData.emit(self.id, U1[i], U2[i])
                self.msleep(10)              # отрегулируйте интервал паузы в мс.

            self.threadFinish.emit(self.id)
            self.msleep(100)                 # отрегулируйте интервал паузы в мс.
            self.threadStart.emit(self.id)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self._chart_view = QtChart.QChartView()
        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        
        lay = QtWidgets.QVBoxLayout(central_widget)
        lay.addWidget(self._chart_view)
        
        self.adjust_axes()
        
        self.thread_1 = Thread(1)                        
        self.thread_1.threadStart.connect(self.print_start)
        self.thread_1.threadData.connect(self.print_func)
        self.thread_1.threadFinish.connect(self.print_finish)
        self.thread_1.start()       

        self.thread_2 = Thread(2)                     
        self.thread_2.threadStart.connect(self.print_start)
        self.thread_2.threadData.connect(self.print_func)
        self.thread_2.threadFinish.connect(self.print_finish)
        self.thread_2.start()        

    def print_start(self, id):
        if id == 1:
            self.scatterU_1 = QtChart.QScatterSeries()
            self.scatterU_1.setColor(Qt.darkGreen)
            self.scatterU_1.setMarkerSize(10.0)
        elif id == 2:
            self.scatterU_2 = QtChart.QScatterSeries()
            self.scatterU_2.setColor(Qt.darkRed)
            self.scatterU_2.setMarkerSize(10.0)            
            
    def print_finish(self, id):
        if id == 1:
            self.window()._chart_view.chart().addSeries(self.scatterU_1)
        elif id == 2:
            self.window()._chart_view.chart().addSeries(self.scatterU_2)
            
    def print_func(self, id, U1, U2):
        if id == 1:
            self.scatterU_1.append(U1, U2)
        elif id == 2:
            self.scatterU_2.append(U1, U2)            

    def adjust_axes(self):
        D1 = np.random.random(50)
        D2 = np.random.random(50)
        chart = QtChart.QChart()
        scatterD = QtChart.QScatterSeries()
        scatterD.setColor(Qt.darkBlue)
        scatterD.setMarkerSize(20.0)
        for i in range(0, 50):
            scatterD.append(D1[i], D2[i])

        chart.addSeries(scatterD)
        chart.createDefaultAxes()
        self._chart_view.setChart(chart)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())

введите сюда описание изображения

→ Ссылка