Answer the question
In order to leave comments, you need to log in
How to work with QThread correctly?
Python 3.4, PyQt 4.8, Windows 10
There is a main thread in which the program itself runs. Inside this thread, I need to start a new thread in the background so that the main thread does not freeze (This main thread is responsible for working with the GUI). From a background thread, some GUI elements need to be changed. I did everything as follows:
In the main form:
self.connect(self.pushButton_4,QtCore.SIGNAL("clicked()"),self.addAllAccounts)
...
...
def addAllAccounts(self):
print("pushButton_4 нажата")
login,password,name=[],[],[]
#Здесь пропущен для удобства кусок, в котором я заполняю login, password, name
#Если массив логинов не пустой, запускаю отдельный тред
if login:
self.pushButton_4.setEnabled(False) #Блокирую кнопку
self.runnable = AThread(login,password,name)
self.runnable.progressed.connect(self.progressBarHandler)
self.runnable.finished.connect(app.exit)
self.runnable.start()
self.label_43.setText("Подождите, добавление займет некоторое время...")
self.progressBar.setMinimum(0)
self.progressBar.setMaximum(len(name))
self.progressBar.setValue(0)
self.progressBar.show()
self.label_43.show()
#Проблема вот в этой строчке
self.runnable.wait() #Если её не использовать, программа падает в случайном месте
#не выдавая ошибок; Если её использовать, GUI замораживается и программа
# подвисает, пока работает фоновый поток
class AThread(QtCore.QThread):
progressed = pyqtSignal()
def __init__(self,logins,passwords,names):
super(AThread,self).__init__()
self.logins=logins
self.passwords=passwords
self.names=names
def run(self):
print(self.logins)
print(self.passwords)
print(self.names)
for i in range(0,len(self.logins)):
login = self.logins[i]
password = self.passwords[i]
name = self.names[i]
checkResult = vk.checkIfValid(login,password)
self.progressed.emit()
Answer the question
In order to leave comments, you need to log in
Can you provide the whole code? Check if simple code works with progress update.
from PyQt4.QtGui import QWidget, QVBoxLayout, QPushButton, QProgressBar, QApplication
from PyQt4.QtCore import QThread, pyqtSignal
import time
class SomeThread(QThread):
progressed = pyqtSignal(int)
def __init__(self):
super().__init__()
def run(self):
for i in range(1, 11):
self.progressed.emit(i)
time.sleep(0.5)
class App(QWidget):
def __init__(self):
super().__init__()
vbox = QVBoxLayout()
self.pBar = QProgressBar()
self.pBar.setMaximum(10)
vbox.addWidget(self.pBar)
self.button = QPushButton("Start")
vbox.addWidget(self.button)
self.thread = None
self.setLayout(vbox)
self.button.clicked.connect(self.on_button)
def on_button(self):
if not self.thread:
self.thread = SomeThread()
self.thread.progressed.connect(self.on_progress)
self.thread.finished.connect(self.on_finished)
self.thread.start()
def on_progress(self, value):
self.pBar.setValue(value)
def on_finished(self):
self.thread.progressed.disconnect(self.on_progress)
self.thread.finished.disconnect(self.on_finished)
self.thread = None
if __name__ == '__main__':
qApp = QApplication([])
app = App()
app.show()
qApp.exec()
I am not a specialist in the internal architecture of Qt, but as I understand it, for the correct interaction of signals and slots from different threads, both must have a working event loop and the connection must be made through some kind of internal queue and not directly (for this, the connected objects must belong to different threads). You have a runnable object on the GUI thread. Perhaps because of this problem. Try to transfer all your manipulations to a separate object of the calculator, the successor of QObject, to the AThread constructor to pass everything you need to communicate with the "outside world", and in the run method create a calculator object by connecting it with signals and slots with objects from the thread's GUI and then calling exec( ) . Here you can see a more detailed article with an example.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question