2013-12-18 15 views
15

ho questo codice:Python PySide e 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_()) 

voglio avere la barra di avanzamento in un thread separato, in modo da non congelare l'applicazione, ma io non riesco a scopri come farlo.

Qualcuno può aiutare per favore?

risposta

25

Penso che potresti sbagliarti. Vuoi il lavoro che stai facendo in un thread separato in modo che non blocchi l'applicazione. Ma vuoi anche essere in grado di aggiornare la barra di avanzamento. È possibile ottenere ciò creando una classe worker usando uno QThread. QThreads sono in grado di emettere segnali, che l'interfaccia utente può ascoltare e agire in modo appropriato.

In primo luogo, creiamo la tua classe di lavoratore.

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

Quindi, ora che avete una classe operaia, è il momento di fare uso di esso. Dovrai creare una nuova funzione nella tua classe Ui_Dialog per gestire i segnali emessi.

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

Già che ci sei, è possibile rimuovere la funzione progress().

in retranslateUi() si vuole aggiornare il gestore di eventi pulsante da

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

a

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

Infine, nella funzione setupUI(), è necessario creare un'istanza della classe operaia e connetti il ​​segnale alla tua funzione setProgress().

Prima di questo:

self.retranslateUi(Dialog) 

Aggiungere questo:

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

Ecco il codice finale:

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 ha alcuni segnali integrati che vengono automaticamente emessi. Potete vederli e ulteriori informazioni su QThreads in the documentation

+1

Sì, è così che volevo che fosse, grazie! – Benny

9

È un errore pensare che sia sempre necessario utilizzare il multi-threading per cose come questa.

Se è possibile suddividere l'attività di lunga durata in una serie di piccoli passaggi, è sufficiente assicurarsi che tutti gli eventi in sospeso vengano elaborati sufficientemente spesso affinché la GUI rimanga reattiva.Questo può essere fatto in modo sicuro dalla all'interno il thread GUI principale utilizzando processEvents, in questo modo:

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

data la sua semplicità, vale sempre la pena almeno considerare questa tecnica prima di optare per una soluzione molto più peso massimo come Multi -threading o multi-processing.

+0

Questo è stato così facile !!! risolto il mio problema !! – user1036908