PyQt progress jumps to 100

后端 未结 2 1557
南方客
南方客 2020-12-04 01:14

When I run the code in the in the doWork method, by clicking the button1, the progress bar works as expected.

However, when I pass the list

相关标签:
2条回答
  • 2020-12-04 01:28

    It seems that you have not understood the logic of my previous solution, I will detail the procedure:

    [1] self.thread = QtCore.QThread()
    [2] self.worker = SeleniumWorker()
    [3] self.worker.moveToThread(self.thread)
    [4] self.worker.progressChanged.connect(progressBar.setValue, QtCore.Qt.QueuedConnection)
    [5] self.thread.started.connect(self.worker.doWork)
    
    1. QThread is a thread handler, so an object of that class allows us to execute a task on a thread other than the main thread called the GUI thread.

    2. You are creating a SeleniumWorker object that has the doWork method, which is a blocking task that should not be executed in the GUI thread, and that will be achieved with the previous QThread.

    3. Since the function must be executed in another thread, the object that has that method must move to that other thread.

    4. The signal of the object that is in the other thread is connected to the QProgressBar that is in the GUI thread, this connection must be made with the flag QtCore.Qt.QueuedConnection.

    5. When the thread is started it will call the doWork function and since the self.worker object is in another thread then the function will also be executed in that other thread.


    In your case in the code that is shown in the next part you are calling the doWork function when the thread has not yet started so it will be executed in the main thread.

    def btn2(self):
        ...
        # main thread
        self.worker.doWork(self.lst2)
    

    One way to pass the urls is through a setter method, and then start the thread. When the thread starts, it will call doWork, and when the doWork is executed, the progressChanged signal will be emited.

    With all the above we obtain the following:

    import sys
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    from selenium import webdriver
    
    class SeleniumWorker(QtCore.QObject):
        progressChanged = QtCore.pyqtSignal(int)
        started = QtCore.pyqtSignal()
        finished = QtCore.pyqtSignal()
        def setUrls(self, urls=['http://www.somesite.com/',
        'http://www.somesite.com/page2',
        'http://www.somesite.com/page3']):
            self.urls = urls
    
        def doWork(self):
            self.started.emit()
            progress = 0
            self.progressChanged.emit(progress)
            browser = webdriver.Firefox()
            links = self.urls
            for link in links:
                browser.get(link)
                progress += 100 / len(links)
                self.progressChanged.emit(progress)
            browser.close()
            self.finished.emit()
    
    class Widget(QtWidgets.QWidget):
        def __init__(self, *args, **kwargs):
            QtWidgets.QWidget.__init__(self, *args, **kwargs)
            lay = QtWidgets.QHBoxLayout(self)
            self.progressBar = QtWidgets.QProgressBar()
            self.progressBar.setRange(0, 100)
            button1 = QtWidgets.QPushButton("Start1")
            button2 = QtWidgets.QPushButton("Start2")
            button3 = QtWidgets.QPushButton("Start3")
            lay.addWidget(self.progressBar)
            lay.addWidget(button1)
            lay.addWidget(button2)
            lay.addWidget(button3)
            self.thread = QtCore.QThread()
            self.worker = SeleniumWorker()
            self.worker.moveToThread(self.thread)
            self.worker.progressChanged.connect(self.progressBar.setValue, QtCore.Qt.QueuedConnection)
            self.thread.started.connect(self.worker.doWork)
            button1.clicked.connect(self.btn1)
            button2.clicked.connect(self.btn2)
            button3.clicked.connect(self.btn3)
            self.worker.finished.connect(self.on_finished)
            self.worker.started.connect(lambda: self.buttons_setEnable(False))
    
        def on_finished(self):
            self.buttons_setEnable(True)
            if self.thread.isRunning():
                self.thread.quit()
                self.thread.wait()
    
        def buttons_setEnable(self, enable):
            for btn in self.findChildren(QtWidgets.QPushButton):
                btn.setEnabled(enable)
    
        def btn1(self):
            self.worker.setUrls()
            self.thread.start()
    
        def btn2(self):
            lst2 = ['http://www.somesite.com/page4',
            'http://www.somesite.com/page5',
            'http://www.somesite.com/page6']
            self.worker.setUrls(lst2)
            self.thread.start()
    
        def btn3(self):
            lst3 = ['http://www.somesite.com/page7',
            'http://www.somesite.com/page8',
            'http://www.somesite.com/page9']
            self.worker.setUrls(lst3)
            self.thread.start()
    
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        w = Widget()
        w.show()
        sys.exit(app.exec_())
    

    Note: I have added the functionality of disabling the buttons while it is running as it is appropriate that the thread does not start again while it is working.

    0 讨论(0)
  • 2020-12-04 01:46

    In my opinion, you have very fast program. Slow down a little.

    QThread.msleep(500)
    

    . ...

        for link in links:
            browser.get(link)
            progress += 100 / len(links)
            self.progressChanged.emit(progress)
    
            QThread.msleep(500)                  # !!!
    

    0 讨论(0)
提交回复
热议问题