問題描述
當我在 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%的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!