Wskaźnik zajętości za pomocą paska postępu PyQt

Próbuję napisać skrypt, który wyświetli wskaźnik zajętości podczas wykonywania zadania. A kiedy zadanie się skończy, pasek postępu wypełni do końca pokazując, że 100% zadanie zostało zakończone. Chcę tylko, aby pasek postępu pokazywał, że zadanie się dzieje.Ale kiedy zacznę zadanie, busy wskazanie stops.It wydaje mi się, że wskazanie i zadanie nie może być kontynuowane razem. Proszę, pomóż mi. Oto mycode:

from PyQt4 import QtCore, QtGui
from time import sleep
try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(344, 159)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.pb = QtGui.QProgressBar(self.centralwidget)
        self.pb.setGeometry(QtCore.QRect(20, 20, 301, 31))
        self.pb.setProperty("value", 0)
        self.pb.setObjectName(_fromUtf8("pb"))
        self.btn = QtGui.QPushButton(self.centralwidget)
        self.btn.setGeometry(QtCore.QRect(20, 70, 98, 27))
        self.btn.setObjectName(_fromUtf8("btn"))
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtGui.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 344, 25))
        self.menubar.setObjectName(_fromUtf8("menubar"))
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtGui.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QObject.connect(self.btn, QtCore.SIGNAL(_fromUtf8("clicked()")), self.action)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)            

    def action(self):
        self.pb.setRange(0, 0)
        sleep(3) # Here I want to run a command.For example: os.system('copy something')
        self.pb.setRange(0, 100)
        self.pb.setValue(100)
        QtGui.qApp.processEvents()

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
        self.btn.setText(_translate("MainWindow", "Start", None))


if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    MainWindow = QtGui.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())
Author: eyllanesc, 2013-10-18

4 answers

Po pierwsze, nie jest dobrym pomysłem, aby bezpośrednio edytować kod utworzony za pomocą QtDesigner. Być może widziałeś linię # WARNING! All changes made in this file will be lost! u góry dokumentu. W przypadku tak prostego widżetu lepiej jest korzystać z ręcznego kodowania.

Po Drugie, przyjrzyj się bliżej temu, co naprawdę robi slot action.

def action(self):
    self.pb.setRange(0, 0) # Un
    sleep(3) # <-- Your slot blocks HERE
    self.pb.setRange(0, 100)
    self.pb.setValue(100)
    QtGui.qApp.processEvents()

Nie ma powodu, aby pasek postępu aktualizował jego wartość, gdy twój slot jest zablokowany w sleep. Po wywołaniu action, wątek gniazda usypia na 3 SEK, a następnie ustawia pasek postępu na pełny 100.

Nie można oczekiwać, że pasek postępu w magiczny sposób zaktualizuje się, gdy twoje zadanie jest uruchomione. Jeśli nie masz pojęcia, jak długo to zajmie i nie możesz podzielić go na etapy, powinieneś rozważyć użycie pulsed ProgressBar (patrz przykład 1 poniżej). Jeśli możesz łatwo uzyskać postęp swojego zadania (powiedzmy kopiowanie n plików), powinieneś odpowiednio zaktualizować wartość paska postępu.

Tak czy inaczej, powinieneś użyć QThread, aby uzyskać zachowanie nieblokujące i signals aby komunikować się między wątkami a główną aplikacją.

  • główna aplikacja uruchamia QThread implementując długo działające zadanie.
  • QThread powiadamia o postępie zadania (jeśli jest dostępny) lub zakończeniu do głównej aplikacji

Przykład 1-Pasek Postępu Impulsu:

Jeśli minimum i maksimum są ustawione na 0, pasek postępu wyświetli wskaźnik zajętości zamiast procentu kroki.

class MyCustomWidget(QtGui.QWidget):

    def __init__(self, parent=None):
        super(MyCustomWidget, self).__init__(parent)
        layout = QtGui.QVBoxLayout(self)

        # Create a progress bar and a button and add them to the main layout
        self.progressBar = QtGui.QProgressBar(self)
        self.progressBar.setRange(0,1)
        layout.addWidget(self.progressBar)
        button = QtGui.QPushButton("Start", self)
        layout.addWidget(button)      

        button.clicked.connect(self.onStart)

        self.myLongTask = TaskThread()
        self.myLongTask.taskFinished.connect(self.onFinished)

    def onStart(self): 
        self.progressBar.setRange(0,0)
        self.myLongTask.start()

    def onFinished(self):
        # Stop the pulsation
        self.progressBar.setRange(0,1)


class TaskThread(QtCore.QThread):
    taskFinished = QtCore.pyqtSignal()
    def run(self):
        time.sleep(3)
        self.taskFinished.emit()  

Przykład 2 - Klasyczny Pasek Postępu:

class MyCustomWidget(QtGui.QWidget):

    def __init__(self, parent=None):
        super(MyCustomWidget, self).__init__(parent)
        layout = QtGui.QVBoxLayout(self)       

        self.progressBar = QtGui.QProgressBar(self)
        self.progressBar.setRange(0,100)
        button = QtGui.QPushButton("Start", self)
        layout.addWidget(self.progressBar)
        layout.addWidget(button)

        button.clicked.connect(self.onStart)

        self.myLongTask = TaskThread()
        self.myLongTask.notifyProgress.connect(self.onProgress)


    def onStart(self):
        self.myLongTask.start()

    def onProgress(self, i):
        self.progressBar.setValue(i)


class TaskThread(QtCore.QThread):
    notifyProgress = QtCore.pyqtSignal(int)
    def run(self):
        for i in range(101):
            self.notifyProgress.emit(i)
            time.sleep(0.1)
 22
Author: Yoann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-14 07:46:02

Wreszcie dostałem to, co chciałem, choć trochę edycji potrzebne . Właśnie dodałem ten tekst do onFinished(): siebie.progressBar.setValue(1) aby potwierdzić 100% wykonanie zadania. Oto kod:

from PyQt4 import QtCore, QtGui
from time import sleep
import sys, os

class MyCustomWidget(QtGui.QWidget):

    def __init__(self, parent=None):
        super(MyCustomWidget, self).__init__(parent)
        layout = QtGui.QVBoxLayout(self)

        # Create a progress bar and a button and add them to the main layout
        self.progressBar = QtGui.QProgressBar(self)
        self.progressBar.setRange(0,1)
        layout.addWidget(self.progressBar)
        button = QtGui.QPushButton("Start", self)
        layout.addWidget(button)      

        button.clicked.connect(self.onStart)

        self.myLongTask = TaskThread()
        self.myLongTask.taskFinished.connect(self.onFinished)

    def onStart(self): 
        self.progressBar.setRange(0,0)
        self.myLongTask.start()

    def onFinished(self):
        # Stop the pulsation
        self.progressBar.setRange(0,1)
        self.progressBar.setValue(1)


class TaskThread(QtCore.QThread):
    taskFinished = QtCore.pyqtSignal()
    def run(self):
        os.system('sudo apt-get install leafpad')
        self.taskFinished.emit() 

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = MyCustomWidget()
    window.resize(640, 480)
    window.show()
    sys.exit(app.exec_())
 3
Author: user2420437,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-02 08:47:08

Trochę późno, ale napisałem szczegółową dokumentację na ten temat, ponieważ wiele osób zdaje się borykać się z tym problemem.

Wprowadzenie do pasków postępu

 1
Author: daegontaven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-24 17:47:19

Zastosuj To:

progressbar.setMinimum(0)
progressbar.setMaximum(0)
progressbar.setValue(0)

To ustawienie będzie miało zajęty wygląd, nie musisz dodawać go do żadnej funkcji, może być w konstruktorze klasy, jeśli chcesz

 0
Author: Arturo Morales Rangel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-25 18:41:40