PyQt进度在启动后跃升至100%

时间:2018-04-04 09:18:28

标签: python selenium pyqt pyqt5 qprogressbar

当我在doWork方法中运行代码时,点击button1,进度条会按预期运行。

但是,当我将列表从其他方法(即doWorkbtn2)传递给btn3方法时,进度条会在启动后跳转到100%。

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
import sys
from selenium import webdriver

class SeleniumWorker(QtCore.QObject):
    progressChanged = QtCore.pyqtSignal(int)
    def doWork(self, lst=['http://www.somesite.com/',
        'http://www.somesite.com/page2',
        'http://www.somesite.com/page3']):
        progress = 0
        browser = webdriver.Firefox()
        links = lst
        for link in links:
            browser.get(link)
            progress += 100 / len(links)
            self.progressChanged.emit(progress)
        browser.close()

class Widget(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        QtWidgets.QWidget.__init__(self, *args, **kwargs)
        lay = QtWidgets.QHBoxLayout(self)
        progressBar = QtWidgets.QProgressBar()
        progressBar.setRange(0, 100)
        button1 = QtWidgets.QPushButton("Start1")
        button2 = QtWidgets.QPushButton("Start2")
        button3 = QtWidgets.QPushButton("Start3")
        lay.addWidget(progressBar)
        lay.addWidget(button1)
        lay.addWidget(button2)
        lay.addWidget(button3)
        self.thread = QtCore.QThread()
        self.worker = SeleniumWorker()
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.doWork)
        button1.clicked.connect(self.thread.start)
        button2.clicked.connect(self.btn2)
        button3.clicked.connect(self.btn3)
        self.worker.progressChanged.connect(progressBar.setValue)


    def btn2(self):
        self.lst2 = ['http://www.somesite.com/page4',
        'http://www.somesite.com/page5',
        'http://www.somesite.com/page6']
        self.worker.doWork(self.lst2)

    def btn3(self):
        self.lst3 = ['http://www.somesite.com/page7',
        'http://www.somesite.com/page8',
        'http://www.somesite.com/page9']
        self.worker.doWork(self.lst3)


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

2 个答案:

答案 0 :(得分:3)

您似乎还没有理解我previous solution的逻辑,我将详细介绍该程序:

[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是一个线程处理程序,因此该类的对象允许我们在称为GUI线程的主线程以外的线程上执行任务。

  2. 您正在创建一个具有doWork方法的SeleniumWorker对象,该方法是一个不应在GUI线程中执行的阻塞任务,并且将使用之前的QThread实现。

  3. 由于该函数必须在另一个线程中执行,因此具有该方法的对象必须移动到该另一个线程。

  4. 另一个线程中对象的信号连接到GUI线程中的QProgressBar,此连接必须使用标志QtCore.Qt.QueuedConnection

  5. 当线程启动时,它将调用doWork函数,并且由于self.worker对象在另一个线程中,因此该函数也将在该另一个线程中执行。

  6. 在您的情况下,在下一部分中显示的代码中,当线程尚未启动时,您正在调用doWork函数,因此它将在主线程中执行。

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

    传递网址的一种方法是通过setter方法,然后启动线程。线程启动时,会调用doWork,执行doWork时,progressChanged信号将被激活。

    综上所述,我们获得了以下内容:

    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_())
    

    注意 :我添加了在按钮运行时禁用按钮的功能,因为线程在工作时不会再次启动

答案 1 :(得分:-3)

在我看来,你的节目非常快。 慢下来一点。

QThread.msleep(500)

。         ...

    for link in links:
        browser.get(link)
        progress += 100 / len(links)
        self.progressChanged.emit(progress)

        QThread.msleep(500)                  # !!!

enter image description here