从Qthread更新Python GUI元素

时间:2015-03-26 01:25:57

标签: python-2.7 pyqt 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元素。我知道两个线程都在运行,但我认为接收信号时遇到问题,因为progressbar没有更新。我尝试了一些东西,但现在我被卡住了。我认为当我尝试将值传递给线程并且当我尝试在`setupUi'方法中创建线程的实例时,问题出现了,只是稍后重新定义它。

任何人都可以帮助并解释我在思考中的错误吗?我试图用线程包围信号和插槽,所以解释会很棒。

1 个答案:

答案 0 :(得分:2)

您的代码存在一些问题,但是您的代码非常接近。

第一个显而易见的是你的主线程中有一个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)    

希望能解释一下!