用多处理程序产生的消息更新qt GUI。

问题描述 投票:0回答:1

我试图将QThread和多进程结合起来,以便能够运行一些长时间的处理任务,同时保持我的GUI响应和更新进程的状态。

下面的代码没有更新标签,直到整个进程结束,所以我只看到最后一条消息。但是 print 工作正常。

import time
from PySide2.QtWidgets import QApplication, QLabel, QWidget, QPushButton, QHBoxLayout
from PySide2.QtCore import QThread, QObject, Signal
from multiprocessing import Process, Queue


class Worker():
    """Worker running in a Process"""
    def __init__(self):
        self.r0 = 2
        self.N = 10

    def setR0(self, r0):
        self.r0 = r0

    def setN(self, n):
        self.N = n

    def task(self, queue):
        for i in range(self.N):
            res = self.r0 ** i
            queue.put(str(i) + ": " + str(res))
            time.sleep(1)
        queue.put("done")


class Runner(QObject):
    """Runner is running in a qthread"""
    messageLogged = Signal(str)

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

    def exec_(self):
        worker = Worker()
        worker.setN(15)
        worker.setR0(3)

        queue = Queue()

        process = Process(target=worker.task, args=(queue,))
        process.start()

        while True:
            msg = queue.get()
            if msg == "done":
                self.messageLogged.emit("received 'done' signal")
                break
            self.messageLogged.emit(msg)

        process.join()


if __name__ == '__main__':
    app = QApplication([])

    widget = QWidget()
    layout = QHBoxLayout()
    widget.setLayout(layout)

    button = QPushButton("Run")
    layout.addWidget(button)

    label = QLabel("initial text")
    layout.addWidget(label)

    thread = QThread()
    r = Runner()
    r.messageLogged.connect(print)
    r.messageLogged.connect(label.setText)
    thread.started.connect(r.exec_)

    def onButtonPushed():
        thread.start()
        button.setEnabled(False)

    button.clicked.connect(onButtonPushed)

    widget.show()
    app.exec_()

为了保持界面的响应性,我还缺少什么?Process但我如何发出一个信号来连接到我的标签?

python multiprocessing pyside2
1个回答
0
投票

我通过删除QThread并使用QTimer代替来解决我的问题。定时器以固定的时间间隔读取队列中的所有消息,然后让GUI再次响应一段时间,直到下次超时。

import time

from PySide2.QtWidgets import QApplication, QLabel, QWidget, QPushButton, QHBoxLayout
from PySide2.QtCore import QTimer
from multiprocessing import Process, Queue


class Worker():
    """Worker running in a Process"""
    def __init__(self):
        self.r0 = 2
        self.N = 10

    def setR0(self, r0):
        self.r0 = r0

    def setN(self, n):
        self.N = n

    def task(self, queue):
        for i in range(self.N):
            res = self.r0 ** i
            queue.put(str(i) + ": " + str(res))
            time.sleep(1)
            print(i)
        queue.put("done")


if __name__ == '__main__':
    app = QApplication([])

    widget = QWidget()
    layout = QHBoxLayout()
    widget.setLayout(layout)

    button = QPushButton("Run")
    layout.addWidget(button)

    label = QLabel("initial text")
    layout.addWidget(label)

    button2 = QPushButton("Kill")
    button2.setEnabled(False)
    layout.addWidget(button2)

    queue = Queue()
    worker = Worker()
    worker.setN(15)
    worker.setR0(3)

    process = Process(target=worker.task, args=(queue, ))

    def read():
        while not queue.empty():
            msg = queue.get()
            if msg == "done":
                label.setText("received 'done' signal")
            else:
                label.setText(msg)

    timer = QTimer()
    timer.timeout.connect(read)

    def onRunButtonPushed():
        print("run clicked")
        process.start()
        timer.start(1000)
        button.setEnabled(False)
        button2.setEnabled(True)

    def onKillButtonPushed():
        process.terminate()
        timer.stop()

    button.clicked.connect(onRunButtonPushed)
    button2.clicked.connect(onKillButtonPushed)

    widget.show()
    app.exec_()
© www.soinside.com 2019 - 2024. All rights reserved.