2013-12-18 13 views
15

tôi có mã này:Python PySide và 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_()) 

Tôi muốn có thanh tiến trình trong một thread riêng biệt, vì vậy nó không đóng băng ứng dụng, nhưng tôi dường như không thể tìm cách làm như vậy.

Mọi người có thể giúp bạn không?

Trả lời

25

Tôi nghĩ bạn có thể bị nhầm lẫn. Bạn muốn công việc bạn đang làm trong một chuỗi riêng biệt để nó không đóng băng ứng dụng. Nhưng bạn cũng muốn có thể cập nhật thanh tiến trình. Bạn có thể đạt được điều này bằng cách tạo một lớp nhân viên bằng cách sử dụng một số QThread. QThreads có thể phát ra tín hiệu, giao diện người dùng của bạn có thể nghe và hành động phù hợp.

Trước tiên, hãy tạo lớp nhân viên của bạn.

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

Vì vậy, bây giờ bạn đã có một lớp công nhân, đã đến lúc tận dụng nó. Bạn sẽ muốn tạo một hàm mới trong lớp Ui_Dialog để xử lý các tín hiệu được phát ra.

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

Khi đang ở đó, bạn có thể xóa chức năng progress().

trong retranslateUi() bạn sẽ muốn cập nhật xử lý sự kiện nút nhấn từ

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

để

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

Cuối cùng, trong chức năng setupUI() của bạn, bạn sẽ cần phải tạo một thể hiện của giai cấp công nhân của bạn và kết nối tín hiệu của nó với chức năng setProgress() của bạn.

Trước đó:

self.retranslateUi(Dialog) 

Thêm này:

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

Đây là mã cuối cùng:

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 có một số tín hiệu tích hợp được tự động phát ra. Bạn có thể xem chúng và thông tin khác về QThreads in the documentation

+1

Yup, đó là cách tôi muốn, cảm ơn! – Benny

9

Đó là một sai lầm khi nghĩ rằng bạn luôn cần phải sử dụng đa luồng cho những thứ như thế này.

Nếu bạn có thể chia công việc dài hạn của mình thành một loạt các bước nhỏ, tất cả những gì bạn cần làm là đảm bảo rằng mọi sự kiện đang chờ xử lý được xử lý đủ thường xuyên để GUI vẫn đáp ứng.Điều này có thể được thực hiện một cách an toàn từ trong thread GUI chính bằng cách sử dụng processEvents, như thế này:

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

Với nó đơn giản, nó luôn luôn giá trị ít nhất là xem xét kỹ thuật này trước khi chọn một giải pháp nhiều nặng hơn như đa -thủ tục hoặc đa xử lý.

+0

Điều này thật dễ dàng !!! giải quyết vấn đề của tôi !! – user1036908