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 flag QtCore.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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…