与 QThreads 通信

Posted

技术标签:

【中文标题】与 QThreads 通信【英文标题】:Communicate with QThreads 【发布时间】:2014-07-24 09:17:36 【问题描述】:

现在(只是为了解释) Main.process() 函数和 WorkerThread.run() 函数是相同的。 它们通过从 listWidget 获取主布局上的值来操作。 我希望我的工作线程类使用我在主列表小部件上设置的参数。

import sys, time
from PyQt4.QtCore import *
from PyQt4.QtGui import *

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

        self.trdprocessbtn = QPushButton("Thread Processing")
        self.guiprocessbtn = QPushButton("Main Processing")

        self.listwidget = QListWidget()
        for i in range(10):
            self.listwidget.addItem(str(i))

        layout = QVBoxLayout()
        layout.addWidget(self.listwidget)
        layout.addWidget(self.guiprocessbtn)
        layout.addWidget(self.trdprocessbtn)
        self.setLayout(layout)

        self.guiprocessbtn.clicked.connect(self.process)

        self.workerthread = WorkerThread()
        self.trdprocessbtn.clicked.connect(self.startthread)

    def startthread(self):
        self.workerthread.start()

    def process(self):
        x = self.listwidget.currentItem().text()
        for i in range(int(x)):
            print "this is main processing ", i 
            time.sleep(1)

    def dialogOpen(self):
        dialog = Dialog()
        dialog.exec_()

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

    def run(self):
        x = self.listwidget.currentItem().text()
        for i in range(int(x)):
            print "This is thread processing ", i 
            time.sleep(1) 


app = QApplication(sys.argv)
form = Main()
form.show()
app.exec_()

【问题讨论】:

您需要添加更多信息。你试过什么?举个例子。 您可以先阅读“如何真正、真正地使用 QThread:mayaposch.wordpress.com/2011/11/01/… 可能更好的链接是:qt-project.org/doc/qt-5/thread-basics.html(我真的不喜欢像给定的那样链接博客或“你错了”-QThread 帖子)所有实现都有正当的理由。官方文档在这里给出了很好的建议 【参考方案1】:

run 方法中的 x = self.listwidget.currentItem().text() 行是错误的。您只能从主/GUI 线程访问小部件。

另一件事是,您的process 插槽块!永远不要阻塞主线程(如果你阻塞了另一个线程,如果你不确定你做对了,你可能做错了)。

修复的简短列表:

去掉线程的run方法,让Qt事件循环也在线程中运行。

QListWidget::currentTextChanged(const QString & currentText) 信号连接到线程和主类中的新插槽,然后使该插槽启动/更新接下来提到的计时器和计数器。

使用QTimer 替换阻塞循环,将timeout 信号连接到执行您现在在循环中执行的操作的插槽。由于您睡了 1 秒钟,因此您应该将计时器设置为每秒关闭一次。由于您只想运行一定的次数,因此请将计数器变量添加到您的类中,并跟踪发生了多少次超时,并在完成时关闭计时器。

如果您需要更复杂的列表数据处理,则在您的主类中为此创建一个槽,将适当的QListWidget 信号连接到它。然后向主类添加一个信号,其中包含线程的已处理数据,您将从该插槽发出该信号。最后,在线程中为线程添加匹配槽以处理您自己的信号发送的数据。您需要这样做,因为(我认为)仅访问 QListWidget 的数据也不是线程安全的。

【讨论】:

如何在任何其他线程中看到主 gui 定义的信号? 我不知道如何用pyqt来做,但是信号和槽是Qt中的一个核心概念。以下是Qt4 和Qt5 的Qt C++ 文档链接,无论您使用的是哪个。这应该让您开始了解这个概念,并允许您搜索如何使用 pyqt 进行操作。 @hoportyo 关于信号和线程。每个 QObject 子类实例都有一些线程亲和性,并且当您将信号连接到一个槽并且对象“生活”在不同线程中时,默认情况下 Qt 将在目标线程中对该信号进行排队,并且在该线程中调用 slot 方法。所以在线程之间连接信号和槽几乎可以自动工作,你不需要担心同步或做任何特别的事情,Qt 会为你做这件事(使用默认的信号/槽连接类型,只要你没有例如,您可以从多个线程访问的全局变量)。 @hoportyo 嗯,还有一点需要注意:如果您对信号和插槽等基本 Qt 概念不清楚,那么您将很难尝试编写多线程代码。 Qt 是基于事件的,你基本上可以做所有没有线程的事情:永远不要阻塞事件循环,只对数据或信号做出反应,然后从你的代码返回到 Qt 事件循环,它会调用你的当它有你的代码要做的事情时再次编码。

以上是关于与 QThreads 通信的主要内容,如果未能解决你的问题,请参考以下文章

使用 QThreads 未正确使用 CPU 内核

Qt 多线程 QThreads 保持 TCP 连接并被重用

Goroutine通信与thread in java间的通信

一起使用 psycopg2 和 Qthreads(或者只是 postgresql 和 qthreads)并更新 GUI

带参数传递的 QThreads

Goroutine通信与thread in java间的通信