error while using QProgressbar PyQt5 python

34 views Asked by At

i have the following code in which I implemented a QprogressDialog it works fine the first time I press the Start button to run the create function but if the dialog finishes and I try to run it again it shows an empty bar that does not increases the progress. any ideas?

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
import time


class Worker(QObject):
    signal = pyqtSignal(int)

    def __init__(self):
        super().__init__()
    @pyqtSlot()
    def do_work(self) -> None:
        for value in range(1,101):
            self.signal.emit(value)
            time.sleep(0.01)
        

class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        self.layout = QVBoxLayout()
        self.con = QWidget()
        self.setCentralWidget(self.con)
        self.con.setLayout(self.layout)
        self.btn = QPushButton("Start",self)
        self.layout.addWidget(self.btn)
        self.thread = QThread()
        self.thread.finished.connect(self.thread_finished)
        self.btn.pressed.connect(self.create)


    def create(self):
        self.p = QProgressDialog("Names", "Cancel", 0, 100)
        self.p.setValue(0)
        self.p.setWindowModality(Qt.ApplicationModal)
        self.p.canceled.connect(self.p.deleteLater)
        self.p.show()
        self.worker = Worker()
        self.worker.signal.connect(self.p.setValue)
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.do_work)
        self.thread.start()

        
        
    def thread_finished(self):
        self.thread.deletelater()
        # self.thread = QThread()
        # self.thread.finished.connect(self.thread_finished)



app = QApplication(sys.argv)
window = Window()
window.show()
app.exec_()

i tried making the dialog a local variable but it does not work either

1

There are 1 answers

0
musicamante On

When do_work finishes, it just returns, but the thread is still alive, so nothing happens when you call again start():

If the thread is already running, this function does nothing.

Besides, deleting and recreating the dialog or the thread is pointless. At most, you need to recreate the worker (assuming it has some instance attributes that will not be used again if restarted), but the most important part is that you have to tell the thread to quit() when your function ends, using a signal in the worker object.

class Worker(QObject):
    signal = pyqtSignal(int)
    finished = pyqtSignal()

    @pyqtSlot()
    def do_work(self) -> None:
        self.keepRunning = True
        for value in range(1,101):
            if not self.keepRunning:
                break
            self.signal.emit(value)
            time.sleep(0.01)
        self.finished.emit()

    def stop(self):
        self.keepRunning = False


class Window(QMainWindow):
    def __init__(self):
        # ...
        self.p = QProgressDialog("Names", "Cancel", 0, 100)
        self.p.setWindowModality(Qt.ApplicationModal)

    def create(self):
        self.p.show()

        self.worker = Worker()
        self.worker.signal.connect(self.p.setValue)
        self.p.canceled.connect(self.worker.stop)

        self.worker.moveToThread(self.thread)
        self.worker.finished.connect(self.thread.quit)

        self.thread.started.connect(self.worker.do_work)
        self.thread.finished.connect(self.worker.deleteLater)
        self.thread.start()

Note: what you had was a problem, not an error.