PyQt progress jumps to 100% after it starts(PyQt 启动后进度跃升至 100%)
问题描述
当我在 doWork
方法中运行代码时,通过单击 button1
,进度条按预期工作.
但是,当我将列表从其他方法(即 btn2
、btn3
)传递给 doWork
方法时,进度条只是跳跃启动后达到 100%.
从 PyQt5 导入 QtCore、QtGui、QtWidgets从 PyQt5.QtWidgets 导入 *从 PyQt5.QtCore 导入 *从 PyQt5.QtGui 导入 *导入系统从硒导入网络驱动程序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']):进度 = 0浏览器 = webdriver.Firefox()链接 = lst对于链接中的链接:browser.get(链接)进度 += 100/len(链接)self.progressChanged.emit(进度)浏览器.close()类小部件(QtWidgets.QWidget):def __init__(self, *args, **kwargs):QtWidgets.QWidget.__init__(self, *args, **kwargs)放置 = QtWidgets.QHBoxLayout(self)progressBar = QtWidgets.QProgressBar()进度条.setRange(0, 100)button1 = QtWidgets.QPushButton("Start1")button2 = QtWidgets.QPushButton("Start2")button3 = QtWidgets.QPushButton("Start3")放置.addWidget(进度条)放置.addWidget(button1)放置.addWidget(按钮2)放置.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.lst2 = ['http://www.somesite.com/page4','http://www.somesite.com/page5','http://www.somesite.com/page6']self.worker.doWork(self.lst2)def btn3(自我):self.lst3 = ['http://www.somesite.com/page7','http://www.somesite.com/page8','http://www.somesite.com/page9']self.worker.doWork(self.lst3)如果 __name__ == '__main__':应用程序 = QtWidgets.QApplication(sys.argv)w = 小部件()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)
李>QThread
是一个线程处理程序,因此该类的对象允许我们在主线程以外的称为 GUI 线程的线程上执行任务.您正在创建一个具有 doWork 方法的 SeleniumWorker 对象,这是一个不应在 GUI 线程中执行的阻塞任务,而这将通过之前的 QThread 来实现.
由于函数必须在另一个线程中执行,具有该方法的对象必须移动到另一个线程.
另一个线程中的对象的信号连接到GUI线程中的
QProgressBar
,这个连接必须使用标志QtCore.Qt.QueuedConnection
.当线程启动时,它会调用 doWork 函数,因为 self.worker 对象在另一个线程中,所以该函数也将在另一个线程中执行.
<小时>
在下一部分显示的代码中,您在线程尚未启动时调用 doWork
函数,因此它将在主线程中执行.
def btn2(self):...# 主线程self.worker.doWork(self.lst2)
<小时>
传递 url 的一种方法是通过 setter 方法,然后启动线程.线程启动时会调用doWork
,当doWork
执行时会发出progressChanged
信号.
通过以上所有内容,我们获得以下内容:
导入系统从 PyQt5 导入 QtCore、QtGui、QtWidgets从硒导入网络驱动程序SeleniumWorker 类(QtCore.QObject):progressChanged = QtCore.pyqtSignal(int)开始 = QtCore.pyqtSignal()完成 = QtCore.pyqtSignal()def setUrls(self, urls=['http://www.somesite.com/','http://www.somesite.com/page2','http://www.somesite.com/page3']):self.urls = 网址定义做工作(自我):self.started.emit()进度 = 0self.progressChanged.emit(进度)浏览器 = webdriver.Firefox()链接 = self.urls对于链接中的链接:browser.get(链接)进度 += 100/len(链接)self.progressChanged.emit(进度)浏览器.close()self.finished.emit()类小部件(QtWidgets.QWidget):def __init__(self, *args, **kwargs):QtWidgets.QWidget.__init__(self, *args, **kwargs)放置 = QtWidgets.QHBoxLayout(self)self.progressBar = QtWidgets.QProgressBar()self.progressBar.setRange(0, 100)button1 = QtWidgets.QPushButton("Start1")button2 = QtWidgets.QPushButton("Start2")button3 = QtWidgets.QPushButton("Start3")放置.addWidget(self.progressBar)放置.addWidget(button1)放置.addWidget(按钮2)放置.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)如果 self.thread.isRunning():self.thread.quit()self.thread.wait()def button_setEnable(self, enable):对于self.findChildren(QtWidgets.QPushButton)中的btn:btn.setEnabled(启用)def btn1(自我):self.worker.setUrls()self.thread.start()def btn2(自我):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(自我):lst3 = ['http://www.somesite.com/page7','http://www.somesite.com/page8','http://www.somesite.com/page9']self.worker.setUrls(lst3)self.thread.start()如果 __name__ == '__main__':应用程序 = QtWidgets.QApplication(sys.argv)w = 小部件()w.show()sys.exit(app.exec_())
注意:我添加了在运行时禁用按钮的功能,因为线程在工作时不会再次启动是合适的.p>
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 to the doWork
method from other methods (i.e. btn2
, btn3
), the progress bar just jumps to 100% after it starts.
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_())
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)
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.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.
Since the function must be executed in another thread, the object that has that method must move to that other thread.
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 flagQtCore.Qt.QueuedConnection
.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.
这篇关于PyQt 启动后进度跃升至 100%的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:PyQt 启动后进度跃升至 100%
基础教程推荐
- 在 Python 中,如果我在一个“with"中返回.块,文件还会关闭吗? 2022-01-01
- 如何在海运重新绘制中自定义标题和y标签 2022-01-01
- 使用PyInstaller后在Windows中打开可执行文件时出错 2022-01-01
- Dask.array.套用_沿_轴:由于额外的元素([1]),使用dask.array的每一行作为另一个函数的输入失败 2022-01-01
- 线程时出现 msgbox 错误,GUI 块 2022-01-01
- 何时使用 os.name、sys.platform 或 platform.system? 2022-01-01
- 筛选NumPy数组 2022-01-01
- 用于分类数据的跳跃记号标签 2022-01-01
- Python kivy 入口点 inflateRest2 无法定位 libpng16-16.dll 2022-01-01
- 如何让 python 脚本监听来自另一个脚本的输入 2022-01-01