正在从 Qthread 更新 Python GUI 元素

Updating Python GUI element from Qthread

所以我知道有很多关于使用 Qthread 在 GUI 中更新元素的帖子。我已经尽力复习了这些,但还有一个问题。

我正在尝试创建一个 GUI,该 GUI 运行 是单击按钮时的一个方法,然后该方法启动一个新线程。然后该线程向 GUI 发出信号以更改 GUI 元素的值:

from PySide import QtCore, QtGui
import time

class WorkerThread(QtCore.QThread):
    updateProgress = QtCore.Signal(int)
    def __init__(self, countto):
        QtCore.QThread.__init__(self)
        self.countto = countto

    def run(self):
        i = 0
        while i <= self.countto:
            print(self.countto)
            self.updateProgress.emit(i)
            time.sleep(1)
            i += 1


class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(400, 300)
        self.progressBar = QtGui.QProgressBar(Dialog)
        self.progressBar.setGeometry(QtCore.QRect(110, 120, 118, 23))
        self.progressBar.setProperty("value", 0)
        self.progressBar.setObjectName("progressBar")
        self.lineEdit = QtGui.QLineEdit(Dialog)
        self.lineEdit.setGeometry(QtCore.QRect(50, 60, 113, 20))
        self.lineEdit.setObjectName("lineEdit")
        self.pushButton = QtGui.QPushButton(Dialog)
        self.pushButton.setGeometry(QtCore.QRect(190, 60, 75, 23))
        self.pushButton.setObjectName("pushButton")

        self.wt = WorkerThread(int)
        self.wt.updateProgress.connect(self.setProgress)

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton.setText(QtGui.QApplication.translate("Dialog", "PushButton", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton.connect(QtCore.SIGNAL('clicked()'), self.get_time)

    def setProgress(self, progress):
        self.progressBar.setValue(progress)

    def get_time(self):
        countto = self.lineEdit.text()
        countto = int(countto)
        print(countto)
        self.wt = WorkerThread(countto)
        self.wt.start()
        q = 0
        while q < 5:
            print(countto+2)
            time.sleep(2)
            q += 1


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    Dialog = QtGui.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

此 GUI 应该 运行 主线程并进行一些任意计数以确保其正常工作。然后第二个线程也进行一些任意计数以确保其正常工作,然后尝试向 GUI 发出信号以更新 progressbar 元素。我知道两个线程都是 运行ning,但我认为我在接收信号时遇到了问题,因为 progressbar 没有更新。我已经尝试了一些事情,但现在我被卡住了。我认为当我尝试将一个值传递给线程以及当我尝试在“setupUi”方法中创建线程的一个实例时,问题就出现了,只是稍后重新定义它。

有谁能帮忙解释一下我的思路错误吗?我正在尝试使用带有线程的信号和槽,所以解释会很好。

您的代码有一些问题,但您已经很接近了。

第一个显而易见的是,您的主线程中有一个带有 time.sleep() 的循环。 Ui_Dialog.get_time() 方法在主线程中运行(它应该如此)。你不应该在那里有任何长的 运行 代码。但是,其中包含 time.sleep(2) 的循环是很长的 运行 代码。就目前而言,您的 GUI 已锁定,因为控制它在 2*countto 秒内未返回到 GUI 事件循环。只需删除整个 while 循环。我真的不知道它为什么在那里。

删除这个:

q = 0
while q < 5:
    print(countto+2)
    time.sleep(2)
    q += 1

下一个问题是因为每次单击按钮时都会重新创建 QThread。因此,对于每个新对象,您需要将该对象中的 updateProgress 信号连接到 setProgress 槽。所以将那里的代码更改为:

self.wt = WorkerThread(countto)        
self.wt.updateProgress.connect(self.setProgress)
self.wt.start()

此时您会看到进度条正确更新。但是,进度条的最大值默认设置为 100。因此,您可能希望在创建线程之前将最大值设置为 countto。例如:

self.progressBar.setMaximum(countto)
self.wt = WorkerThread(countto)    

希望能解释清楚!