Python PySide and Progress Bar Threading
我有以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | from PySide import QtCore, QtGui import time class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(400, 133) self.progressBar = QtGui.QProgressBar(Dialog) self.progressBar.setGeometry(QtCore.QRect(20, 10, 361, 23)) self.progressBar.setProperty("value", 24) self.progressBar.setObjectName("progressBar") self.pushButton = QtGui.QPushButton(Dialog) self.pushButton.setGeometry(QtCore.QRect(20, 40, 361, 61)) self.pushButton.setObjectName("pushButton") 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.progressBar.setValue(0) self.pushButton.clicked.connect(self.progress) def progress(self): self.progressBar.minimum = 1 self.progressBar.maximum = 100 for i in range(1, 101): self.progressBar.setValue(i) time.sleep(0.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_()) |
我希望将进度条放在单独的线程中,因此它不会冻结应用程序,但是我似乎找不到如何这样做。
有人可以帮忙吗?
我认为您可能会误会。您需要在单独的线程中进行工作,以免冻结应用程序。但是您还希望能够更新进度条。您可以通过使用
首先,让我们创建您的工作程序类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #Inherit from QThread class Worker(QtCore.QThread): #This is the signal that will be emitted during the processing. #By including int as an argument, it lets the signal know to expect #an integer argument when emitting. updateProgress = QtCore.Signal(int) #You can do any extra things in this init you need, but for this example #nothing else needs to be done expect call the super's init def __init__(self): QtCore.QThread.__init__(self) #A QThread is run by calling it's start() function, which calls this run() #function in it's own"thread". def run(self): #Notice this is the same thing you were doing in your progress() function for i in range(1, 101): #Emit the signal so it can be received on the UI side. self.updateProgress.emit(i) time.sleep(0.1) |
现在,您有了工作程序类。 ,是时候利用它了。您将要在
1 2 | def setProgress(self, progress): self.progressBar.setValue(progress) |
在那里,您可以删除您的
在
<更新按钮事件处理程序。 zzu2>
to
1 | self.pushButton.clicked.connect(self.worker.start) |
最后,在您的
在此之前:
1 | self.retranslateUi(Dialog) |
添加此:
1 2 | self.worker = Worker() self.worker.updateProgress.connect(self.setProgress) |
这是最终代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | from PySide import QtCore, QtGui import time class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName("Dialog") Dialog.resize(400, 133) self.progressBar = QtGui.QProgressBar(Dialog) self.progressBar.setGeometry(QtCore.QRect(20, 10, 361, 23)) self.progressBar.setProperty("value", 24) self.progressBar.setObjectName("progressBar") self.pushButton = QtGui.QPushButton(Dialog) self.pushButton.setGeometry(QtCore.QRect(20, 40, 361, 61)) self.pushButton.setObjectName("pushButton") self.worker = Worker() self.worker.updateProgress.connect(self.setProgress) self.retranslateUi(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog) self.progressBar.minimum = 1 self.progressBar.maximum = 100 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.progressBar.setValue(0) self.pushButton.clicked.connect(self.worker.start) def setProgress(self, progress): self.progressBar.setValue(progress) #Inherit from QThread class Worker(QtCore.QThread): #This is the signal that will be emitted during the processing. #By including int as an argument, it lets the signal know to expect #an integer argument when emitting. updateProgress = QtCore.Signal(int) #You can do any extra things in this init you need, but for this example #nothing else needs to be done expect call the super's init def __init__(self): QtCore.QThread.__init__(self) #A QThread is run by calling it's start() function, which calls this run() #function in it's own"thread". def run(self): #Notice this is the same thing you were doing in your progress() function for i in range(1, 101): #Emit the signal so it can be received on the UI side. self.updateProgress.emit(i) time.sleep(0.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_()) |
QThreads具有一些内置信号会自动发出。您可以在文档中找到它们,以及有关QThreads的更多信息
认为您总是需要对此类事情使用多线程是一个错误。
如果您可以将长时间运行的任务分解为一系列小步骤,那么您要做的就是确保足够频繁地处理任何未决事件,以使GUI保持响应。可以使用processEvents在主GUI线程中安全地完成此操作,如下所示:
1 2 3 4 | for i in range(1, 101): self.progressBar.setValue(i) QtGui.qApp.processEvents() time.sleep(0.1) |
鉴于其简单性,在选择一个更重量级的解决方案,例如多线程或多处理。