从 Qthread 更新 Python GUI 元素 [英] Updating Python GUI element from Qthread

查看:58
本文介绍了从 Qthread 更新 Python GUI 元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

So I know there are a lot of posts about updating elements in a GUI with Qthread. I did my best to go over these, but still have a question.

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

I'm trying to create a GUI that runs a method when a button is clicked and that method then starts a new thread. Then that thread emits a signal to the GUI to change the value of the GUI element:

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' 方法中创建线程的实例时,问题就出现了,只是为了稍后重新定义它.

This GUI is supposed to run the main thread and do some arbitrary counting to make sure it's working. Then the second thread does some arbitrary counting as well to make sure it's working and then attempts to emit a signal to the GUI to update the progressbar element. I know both threads are running, but I think I'm having a problem receiving the signal because the progressbar isn't updating. I've tried a few things, but now I'm stuck. I think the problem comes up when I try to pass a value to the thread and when I try to create an instance of the thread in the `setupUi' method, only to redefine it later on.

谁能帮我解释一下我的思维错误?我正在尝试使用带有线程的信号和插槽来解决我的问题,所以解释会很好.

Could anyone help and explain my error in thinking? I'm trying to wrap my head around using signals and slots with threading, so an explanation would be great.

推荐答案

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

There are a few things wrong with your code, however you were pretty close.

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

The first obvious one is that you have a loop with a time.sleep() in your main thread. The Ui_Dialog.get_time() method runs in the main thread (as it should). You should not have any long running code there. However, the loop with the time.sleep(2) in it is long running code. As it stands now, your GUI locks up because control it not returned to the GUI event loop for 2*countto seconds. Just remove the whole while loop. I don't really know why it is there.

删除:

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

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

The next issue comes because you recreate the QThread each time you click the button. As such, for each new object, you need to connect the updateProgress signal in that object to the setProgress slot. So change the code there to:

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

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

At this point you will see the progress bar update correctly. However, the maximum value of the progress bar is set to 100 by default. So you might want to set the maximum value to countto just before you create the thread. For example:

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

希望能解释一切!

这篇关于从 Qthread 更新 Python GUI 元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆