2013-12-18 15 views
15

Ich habe diesen Code:Python pyside und Progress Bar Threading

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_()) 

Ich mag die Fortschrittsbalken in einem separaten Thread haben, so dass er die Anwendung nicht einfrieren, aber ich kann nicht scheinen zu finde, wie es geht.

Kann mir bitte jemand helfen?

Antwort

25

Ich denke, dass Sie sich irren können. Sie möchten, dass Ihre Arbeit in einem separaten Thread ausgeführt wird, damit die Anwendung nicht eingefroren wird. Aber Sie möchten auch den Fortschrittsbalken aktualisieren können. Sie können dies erreichen, indem Sie eine Worker-Klasse mit einer QThread erstellen. QThreads sind in der Lage, Signale auszusenden, auf die Ihre UI hören und entsprechend reagieren kann.

Zuerst erstellen wir Ihre Worker-Klasse.

#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) 

Jetzt, wo Sie eine Arbeiterklasse haben, ist es Zeit, sie zu nutzen. Sie möchten eine neue Funktion in Ihrer Klasse Ui_Dialog erstellen, um die emittierten Signale zu verarbeiten.

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

Während Sie dort sind, können Sie Ihre progress() Funktion entfernen.

in retranslateUi() wollen Sie den Druckknopf-Ereignishandler von

self.pushButton.clicked.connect(self.progress) 

zu

self.pushButton.clicked.connect(self.worker.start) 

schließlich zu aktualisieren, in Ihrer setupUI() Funktion, müssen Sie eine Instanz der Arbeiter-Klasse erstellen und verbinden Sie das Signal mit Ihrer setProgress() Funktion.

Vor diesem:

self.retranslateUi(Dialog) 

Fügen Sie diese:

self.worker = Worker() 
self.worker.updateProgress.connect(self.setProgress) 

Hier ist der endgültige Code:

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 haben einige eingebaute Signale, die automatisch ausgesendet werden. Sie können sie sehen, und weitere Informationen über QThreads in the documentation

+1

Yup, so wollte ich es haben, danke! – Benny

9

Es ist ein Fehler zu denken, dass Sie immer Multithreading für solche Dinge verwenden müssen.

Wenn Sie Ihre langwierige Aufgabe in eine Reihe von kleinen Schritten aufteilen können, müssen Sie nur sicherstellen, dass ausstehende Ereignisse ausreichend oft verarbeitet werden, damit die GUI weiterhin reagiert.Dies kann durch Verwendung processEvents, wie diese sicher aus dem innerhalb der Haupt GUI-Thread erfolgen:

for i in range(1, 101): 
     self.progressBar.setValue(i) 
     QtGui.qApp.processEvents() 
     time.sleep(0.1) 

Aufgrund seiner Einfachheit ist es immer wert zumindest diese Technik unter Berücksichtigung vor wie Multi für eine viel Schwergewichts-Lösung entscheiden - Threading oder Multi-Processing.

+0

Das war so einfach !!! löste mein Problem !! – user1036908