2013-12-18 13 views
15

mam ten kod:Python PySide i 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_()) 

Chcę mieć pasek postępu w osobnym wątku, więc nie zamrażać aplikację, ale nie wydaje się dowiedzieć się, jak to zrobić.

Czy ktoś może pomóc?

Odpowiedz

25

Myślę, że możesz się mylić. Chcesz pracy, którą robisz w osobnym wątku, aby nie zamrozić aplikacji. Ale chcesz też móc aktualizować pasek postępu. Możesz to osiągnąć, tworząc klasę robotniczą przy użyciu QThread. QThreads są w stanie emitować sygnały, które twój interfejs użytkownika może nasłuchiwać i działać właściwie.

Najpierw utwórzmy klasę robotniczą.

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

Teraz, gdy masz już klasę robotniczą, czas ją wykorzystać. Będziesz chciał utworzyć nową funkcję w klasie Ui_Dialog do obsługi emitowanych sygnałów.

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

Będąc na miejscu, można usunąć funkcję progress().

w retranslateUi() będzie chcesz zaktualizować obsługi zdarzeń przyciskowy z

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

do

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

Wreszcie w swojej funkcji setupUI(), trzeba będzie utworzyć instancję klasy pracownika i podłącz go do swojej funkcji setProgress().

Przed tym:

self.retranslateUi(Dialog) 

Dodaj to:

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

Oto ostateczny kod:

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 mają wbudowane sygnały, które są automatycznie emitowane. Możesz je zobaczyć i więcej informacji o QThreads in the documentation

+1

Tak, tak chciałem, dzięki! – Benny

9

Błędem jest myślenie, że zawsze musisz używać wielowątkowości do takich rzeczy.

Jeśli możesz podzielić swoje długo działające zadanie na kilka małych kroków, wszystko, co musisz zrobić, to upewnić się, że wszelkie oczekujące zdarzenia są przetwarzane wystarczająco często, aby interfejs graficzny pozostał responsywny.Można to zrobić bezpiecznie z w główny wątek GUI za pomocą processEvents, tak:

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

Biorąc to prostota, to zawsze warto przynajmniej biorąc pod uwagę tę technikę przed decydując się na znacznie bardziej heavyweight rozwiązania jak wielo -trasowanie lub wielokrotne przetwarzanie.

+0

To było takie łatwe !!! rozwiązał mój problem !! – user1036908