PyQt 中带有 QThread 的后台线程

新手上路,请多包涵

我有一个程序,它通过我在 PyQt 中编写的 gui 与我正在使用的收音机接口。显然无线电的主要功能之一是传输数据,但要连续执行此操作,我必须循环写入,这会导致 gui 挂起。由于我从未处理过线程,我尝试使用 QCoreApplication.processEvents(). 来摆脱这些挂起 --- 不过,无线电需要在传输之间休眠,因此 gui 仍然会根据这些休眠持续的时间而挂起。

有没有一种简单的方法可以使用 QThread 解决这个问题?我一直在寻找有关如何使用 PyQt 实现多线程的教程,但其中大部分都是关于设置服务器的,而且比我需要的要高级得多。老实说,我什至不需要我的线程在运行时更新任何东西,我只需要启动它,让它在后台传输,然后停止它。

原文由 gwenger 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

我创建了一个小示例,展示了处理线程的 3 种不同且简单的方法。我希望它能帮助您找到解决问题的正确方法。

 import sys
import time

from PyQt5.QtCore import (QCoreApplication, QObject, QRunnable, QThread,
                          QThreadPool, pyqtSignal)

# Subclassing QThread
# http://qt-project.org/doc/latest/qthread.html
class AThread(QThread):

    def run(self):
        count = 0
        while count < 5:
            time.sleep(1)
            print("A Increasing")
            count += 1

# Subclassing QObject and using moveToThread
# http://blog.qt.digia.com/blog/2007/07/05/qthreads-no-longer-abstract
class SomeObject(QObject):

    finished = pyqtSignal()

    def long_running(self):
        count = 0
        while count < 5:
            time.sleep(1)
            print("B Increasing")
            count += 1
        self.finished.emit()

# Using a QRunnable
# http://qt-project.org/doc/latest/qthreadpool.html
# Note that a QRunnable isn't a subclass of QObject and therefore does
# not provide signals and slots.
class Runnable(QRunnable):

    def run(self):
        count = 0
        app = QCoreApplication.instance()
        while count < 5:
            print("C Increasing")
            time.sleep(1)
            count += 1
        app.quit()

def using_q_thread():
    app = QCoreApplication([])
    thread = AThread()
    thread.finished.connect(app.exit)
    thread.start()
    sys.exit(app.exec_())

def using_move_to_thread():
    app = QCoreApplication([])
    objThread = QThread()
    obj = SomeObject()
    obj.moveToThread(objThread)
    obj.finished.connect(objThread.quit)
    objThread.started.connect(obj.long_running)
    objThread.finished.connect(app.exit)
    objThread.start()
    sys.exit(app.exec_())

def using_q_runnable():
    app = QCoreApplication([])
    runnable = Runnable()
    QThreadPool.globalInstance().start(runnable)
    sys.exit(app.exec_())

if __name__ == "__main__":
    #using_q_thread()
    #using_move_to_thread()
    using_q_runnable()

原文由 aukaost 发布,翻译遵循 CC BY-SA 3.0 许可协议

将此答案更新为 PyQt5,python 3.4

使用它作为模式来启动一个不获取数据并返回数据的工作程序,因为它们可用于表单。

1 - Worker 类变得更小,并放在自己的文件 worker.py 中,以便于记忆和独立的软件重用。

2 - main.py 文件是定义 GUI Form 类的文件

3 - 线程对象未被子类化。

4 - thread对象和worker对象都属于Form对象

5 - 程序步骤在评论中。

 # worker.py
from PyQt5.QtCore import QThread, QObject, pyqtSignal, pyqtSlot
import time

class Worker(QObject):
    finished = pyqtSignal()
    intReady = pyqtSignal(int)

    @pyqtSlot()
    def procCounter(self): # A slot takes no params
        for i in range(1, 100):
            time.sleep(1)
            self.intReady.emit(i)

        self.finished.emit()

主文件是:

   # main.py
  from PyQt5.QtCore import QThread
  from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QGridLayout
  import sys
  import worker

  class Form(QWidget):

    def __init__(self):
       super().__init__()
       self.label = QLabel("0")

       # 1 - create Worker and Thread inside the Form
       self.obj = worker.Worker()  # no parent!
       self.thread = QThread()  # no parent!

       # 2 - Connect Worker`s Signals to Form method slots to post data.
       self.obj.intReady.connect(self.onIntReady)

       # 3 - Move the Worker object to the Thread object
       self.obj.moveToThread(self.thread)

       # 4 - Connect Worker Signals to the Thread slots
       self.obj.finished.connect(self.thread.quit)

       # 5 - Connect Thread started signal to Worker operational slot method
       self.thread.started.connect(self.obj.procCounter)

       # * - Thread finished signal will close the app if you want!
       #self.thread.finished.connect(app.exit)

       # 6 - Start the thread
       self.thread.start()

       # 7 - Start the form
       self.initUI()

    def initUI(self):
        grid = QGridLayout()
        self.setLayout(grid)
        grid.addWidget(self.label,0,0)

        self.move(300, 150)
        self.setWindowTitle('thread test')
        self.show()

    def onIntReady(self, i):
        self.label.setText("{}".format(i))
        #print(i)

    app = QApplication(sys.argv)

    form = Form()

    sys.exit(app.exec_())

原文由 Raiden Core 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题