当前位置: 首页 > 面试题库 >

PyQt进度在开始后跃升至100%

欧阳德运
2023-03-14
问题内容

当我在doWork方法中运行时,通过单击button1,进度条将按预期工作。

然而,当我通过列表中的doWork其他方法的方法(即btn2btn3),进度条刚跳到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_())

问题答案:

看来您不了解我先前解决方案的逻辑,我将详细说明该过程:

[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. 另一个线程中的对象的信号连接到QProgressBarGUI线程中的对象,该连接必须使用flag进行QtCore.Qt.QueuedConnection

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

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

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

传递url的一种方法是通过setter方法,然后启动线程。线程启动时,将调用doWorkdoWork执行时,将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_())

注意 :我添加了在按钮运行时禁用按钮的功能,因为适当的是,线程在运行时不要再次启动。



 类似资料:
  • 问题内容: 当我在方法中运行代码时,通过点击,进度条将按预期工作。 然而,当我通过列表中的其他方法的方法(即,),进度条刚跳到100%它启动后。 问题答案: 看来您不了解我先前解决方案的逻辑,我将详细说明该过程: 是线程处理程序,因此该类的对象使我们可以在除主线程(称为GUI线程)之外的其他线程上执行任务。 您正在创建一个具有doWork方法的SeleniumWorker对象,该对象是不应在GUI

  • PS Vita的系统软件可通过升级,追加各式各样的功能或强化安全性。使用时请随时升级为最新版本。 若要进行系统升级,需事先将连接的电脑设为以下状态。 连接互联网 安装/下载PlayStation®内容管理助手 可在以下网站进行下载。 http://cma.dl.playstation.net/cma/ 1. 在电脑确认内容管理助手是否已启动。 可从电脑的工作列确认。 2. 使用USB连接线连接PS

  • PS Vita的系统软件可通过升级,追加各式各样的功能或强化安全性。使用时请随时升级为最新版本。 若要进行升级,需事先将连接的PS3™设为以下状态。 连接互联网 系统软件升级为版本4.00以上 关闭所有使用中的应用程序,显示(用户) 1. 使用USB连接线连接PS Vita和PS3™。 2. 操作PS Vita,轻触[系统升级]>[连接至PS3™进行升级]。 可通过PS3™的网络功能,经由互联网下

  • 问题内容: 我有一个奇怪的场景,其中SQL Server 2012数据库中的自动标识int列未正确递增。 假设我有一个使用int自动标识作为主键的表,它偶尔会跳过增量,例如: 1,2,3,4,5,1004,1005 这是在非常随机的时间在随机数量的表上发生的,无法复制以找到任何趋势。 这是怎么回事?有没有办法使它停止? 问题答案: 这完全是正常的。微软在SQL Server 2012中添加了,最后

  • 问题内容: 这是在PyQt4,Linux和Python 2.5上 我可以将PyQt的窗口设置为“始终位于其他应用程序之上”吗? 例如,在GTK中,我使用属性:Modal。 现在,在PyQt中,我正在使用QWidget,但是,我找不到一种方法来实现。 有任何想法吗?? 问题答案: 向QMainWindow传递 窗口标志(或使用setWindowFlags)。 顾名思义,这是对窗口管理器的提示(不是硬

  • 问题内容: 我正在尝试编写一个脚本,该脚本在执行任务时将显示忙碌指示。任务结束后,进度条将填满,表明任务已完成100%。我只是希望进度条显示任务正在进行中,但是当我启动任务时,忙碌的指示停止了。在我看来,指示和任务无法一起继续进行。请帮我。这是mycode: 问题答案: 首先,直接编辑使用QtDesigner创建的代码是一个坏主意。您可能已经在文档顶部看到该行。对于这样一个简单的小部件,最好使用手