在 PyQt4 中使用 QThread 运行线程时更新变量值

Posted

技术标签:

【中文标题】在 PyQt4 中使用 QThread 运行线程时更新变量值【英文标题】:Updating variable values when running a thread using QThread in PyQt4 【发布时间】:2017-10-17 02:20:00 【问题描述】:

所以当我尝试在我的代码中使用Threading 时出现了问题。我想要做的是将默认值传递给def __init__,然后使用其实例调用具有更新值的线程,但不知何故我无法获得更新的值。下面是我的初始代码:ma​​in .py

from PyQt4 import QtGui
import sys
import GUI # GUI app by using PYQT4
from PyQt4.QtCore import QThread
#import Photos

class PyMain(QtGui.QWidget, GUI.Ui_Pycloud):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self)
        self.password.setEchoMode(QtGui.QLineEdit.Password)

        """Picking up data from GUI.py file where initially,
        it is set to 'Username' and 'Password' respectively.
        and initialising `GetThread` class"""
        self.get_thread = GetThread(str(self.username.text()), 
                                    str(self.password.text())
                                   )
        """This is what I was initially using.
           I have tried, only passing the instance and calling 
           get_thread.start() inside __init__ fn but even if i don't click 
           `commandLinkButton` it is somehow called automatically.
           I know it is not the right approach"""
        self.commandLinkButton.clicked.connect(self.get_thread.start)


class GetThread(QThread):

    def __init__(self, username, password):
        QThread.__init__(self)
        self.username = username
        self.password = password

    def __del__(self):
        self.wait()

    def authentication(self):
        print self.username, self.password
        # user = Photos.PyPhotos(self.username, self.password)
        # user.authentication(user)

    def run(self):
        self.authentication()


def main():
    app = QtGui.QApplication(sys.argv)
    form = PyMain()
    form.show()
    app.exec_()

if __name__ == '__main__':
    main()

以下是我尝试过的:

...........................
...........................
...........................

class PyMain(QtGui.QWidget, GUI.Ui_Pycloud):
  def __init__(self):
    super(self.__class__, self).__init__()
    self.setupUi(self)
    self.password.setEchoMode(QtGui.QLineEdit.Password)
    self.commandLinkButton.clicked.connect(GetThread(str(self.username.text()), 
                                             str(self.password.text())).__init__)

class GetThread(QThread):

 def __init__(self, username, password):
        QThread.__init__(self)
        self.username = username
        self.password = password
        self.start()
...........................
...........................
...........................

结果: Username Password

当我运行我的main.py 文件时会显示它,而我应该得到这个只有当我按下commandLinkButton 并且如果我在我的 GUI 上更新它们没有发生时应该更新变量。

编辑:以下是我再次尝试的方法,如果我在 GUI 上更新它们,它会向我显示正确的输出,但在这种情况下线程不起作用:

..............
..............
..............
class PyMain(QtGui.QWidget, GUI.Ui_Pycloud):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self)
        self.password.setEchoMode(QtGui.QLineEdit.Password)
        self.commandLinkButton.clicked.connect(self.populate)

    def populate(self):
        get_thread = GetThread(str(self.username.text()), str(self.password.text()))
        get_thread.start()


class GetThread(QThread):

    def __init__(self, username, password):
        QThread.__init__(self)
        self.username = username
        self.password = password

    def __del__(self):
        self.wait()

    def authentication(self):
        print self.username, self.password
        user = Photos.PyPhotos(self.username, self.password)
        user.authentication(user)

    def run(self):
        self.authentication()
......................
......................
......................

那么任何人都可以请告诉我如何处理这个问题?

【问题讨论】:

【参考方案1】:

您需要使用自定义信号将身份验证结果发送回主线程。但请注意,您不得在主线程之外执行任何类型的 gui 操作。因此,例如,工作线程无法显示身份验证对话框或尝试直接更新小部件。它所能做的就是执行一个冗长的非 gui 进程,并在完成后将结果发送回主线程。

代码的基本结构应该是这样的:

class PyMain(QtGui.QWidget, GUI.Ui_Pycloud):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.setupUi(self)
        self.password.setEchoMode(QtGui.QLineEdit.Password)
        self.commandLinkButton.clicked.connect(self.populate)

    def populate(self):
        self.thread = GetThread(self.username.text(), self.password.text())
        self.thread.authResult.connect(self.handleAuthResult)
        self.thread.start()

    def handleAuthResult(self, result):
        # do something with result...

class GetThread(QThread):
    authResult = QtCore.pyqtSignal(object)

    def __init__(self, username, password):
        QThread.__init__(self)
        self.username = username
        self.password = password

    def authentication(self):
        result = do_authentication()
        self.authResult.emit(result)

    def run(self):
        self.authentication()

【讨论】:

工作完美。对 PyQt 和线程来说有点新,谢谢分享。 (竖起大拇指)-@ekhumoro 既然我们在 PyQt 上,你能推荐任何帖子/博客来链接两个不同的 GUI - @ekhumoro @Aadit。别客气。我不确定“链接两个不同的 GUI”是什么意思。也许你应该发布一个新问题? 我只想在我的 main.py 文件上单击按钮打开指令.py(Qt 设计器创建的对话框窗口)文件。我尝试了一些方法,但遇到了问题。所以我应该发布这是一个问题吗? @Aadit。导入对话框类,然后像PyMain一样创建它的子类。然后在连接到按钮的插槽中,执行self.dialog = DialogSubClass(); self.dialog.show()

以上是关于在 PyQt4 中使用 QThread 运行线程时更新变量值的主要内容,如果未能解决你的问题,请参考以下文章

QThread:线程仍在运行时被销毁?

QThread:在线程仍在运行时被销毁

QThread:在线程仍在运行时被销毁

带有 QThread 和线程模块的 Python 多线程

在qthread中停止长时间运行的进程

在 qthread 中停止长时间运行的进程