首页 > 解决方案 > Python PyQt 将后端与 GUI 分开

问题描述

我希望我的 Python 后端不必等待我的 PyQt GUI 来绘制(很多)东西。在 PyQt 中是否有比下面的代码示例更好/正确的方法?是否有必要使用线程导入或者 PyQt 有自己更好的方法?

import time
from threading import Thread

class Backend(Thread):
    def __init__(self):
        super().__init__()

    def run(self):
        for i in range(20):
            print("Backend heavy work")
            time.sleep(4)


class GUI(Thread):
    def __init__(self):
        super().__init__()

    def run(self):
        for i in range(20):
            print("GUI drawing stuff")
            time.sleep(0.5)

if __name__ == '__main__':
    thread_backend = Backend()
    thread_gui = GUI()

    thread_backend.start()
    thread_gui.start()

我尝试使用 Qtimer 进行操作,但没有成功。谢谢!

标签: pythonmultithreadingpyqt

解决方案


您不能从 Qt 循环之外更新 UI。您可以做的是使用 qt 信号连接到为您完成工作的方法。举个例子

class GUI(QtCore.QObject): # must be a class that inherits QObject to use signals, I believe
    drawSignal = QtCore.pyqtSignal(int)
    def __init__(self):
        super().__init__()
        self.drawSignal.connect(self._drawStuff) # The underscore thing is a little hacky, but sort of pythonic I think, and makes the API clean.
        self.drawStuff = self.drawSignal.emit
    def _drawStuff(self, i):
        # do whatever you want to the gui here
        pass


class GUILoop(Thread):
    def __init__(self, gui):
        super().__init__()
        self.gui = gui
    def run(self):
        for i in range(20):
            self.gui.drawStuff(i)
            time.sleep(0.5)

if __name__ == '__main__':
    gui = GUI()
    thread_backend = Backend()
    thread_gui = GUILoop(gui)

    thread_backend.start()
    thread_gui.start()

这可能看起来有点奇怪,但它非常适合 Qt 和 Python 的优势。将信号添加到QMainWindow已经是QObject.


推荐阅读