Pyqt5 qthread + signal ne fonctionne pas + gui gel
Je suis en train de faire une boîte aux lettres checker avec imap
lib, il fonctionne assez bien avec python, la file d'attente et multithread sans gui.
Mais quand j'ai essayer de mettre une interface graphique, chaque fonction que j'ai fait, faire de la gui congeler jusqu'à la fin .
J'ai essayé beaucoup de chose à partir de divers doc(ajouter qthread, signal, cursorr etcc) et tutoriels aucun n'a fonctionné pour moi .
Quelqu'un peut m'aider à comprendre comment le régler ou ajouter un texte à un QtextEdit lors de l'exécution d'une fonction coz il travail qu'après avoir terminer .
Voici mon code :
class Checker(QtCore.QThread):
signal = QtCore.pyqtSignal(object)
def __init__(self, lignesmailtocheck):
QtCore.QThread.__init__(self)
self.lignesmailtocheck = lignesmailtocheck
def run(self):
lignemailtocheck = self.lignesmailtocheck.strip()
maillo, passo = lignemailtocheck.split(":",1)
debmail, finmail = maillo.split("@",1)
setimap =["oultook.com:imap-mail.outlook.com", "gmail.com:imap.gmail.com"]
for lignesimaptocheck in sorted(setimap):
ligneimaptocheck = lignesimaptocheck.strip()
fai, imap = ligneimaptocheck.split(":",1)
if finmail == fai:
passo0 = passo.rstrip()
try :
mail = imaplib.IMAP4_SSL(imap)
mail.login(maillo, passo)
mailboxok = open("MailBoxOk.txt", "a+", encoding='utf-8', errors='ignore')
mailboxok.write(maillo+":"+passo+"\n")
mailboxok.close()
totaly = maillo+":"+passo0+":"+imap
print(maillo+":"+passo+"\n")
self.send_text.emit(totaly)
time.sleep(1)
except imaplib.IMAP4.error:
print ("LOGIN FAILED!!! ")
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(150, 210, 75, 23))
self.pushButton.setObjectName("pushButton")
self.pushButton.clicked.connect(self.gogogo)
self.openliste = QtWidgets.QToolButton(Form)
self.openliste.setGeometry(QtCore.QRect(40, 110, 71, 21))
self.openliste.setObjectName("openliste")
self.textEdit = QtWidgets.QTextEdit(Form)
self.textEdit.setGeometry(QtCore.QRect(170, 50, 201, 121))
self.textEdit.setObjectName("textEdit")
self.progressBar = QtWidgets.QProgressBar(Form)
self.progressBar.setGeometry(QtCore.QRect(10, 260, 381, 23))
self.progressBar.setValue(0)
self.progressBar.setObjectName("progressBar")
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton.setText(_translate("Form", "PushButton"))
self.openliste.setText(_translate("Form", "..."))
def gogogo(self):
mailtocheck = open('File/toCheck.txt', 'r', encoding='utf-8', errors='ignore').readlines()
setmailtocheck = set(mailtocheck)
for lignesmailtocheck in sorted(setmailtocheck):
checker = Checker(lignesmailtocheck)
thread = QThread()
checker.moveToThread(thread)
# connections after move so cross-thread:
thread.started.connect(checker.run)
checker.signal.connect(self.checkedok)
thread.start()
def checkedok(self, data):
print(data)
self.textEdit.append(data)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
Vous devez décrire les étapes pour reproduire le problème. Lorsque je l'exécute (après la suppression d'un couple de lignes d'importations), et cliquez sur le bouton, je vois YY imprimé à la console, mais pas de gel. Merci de poster le code qui provoque le problème, avec les étapes pour obtenir le gel, et nous pouvons vous aider à résoudre ce problème.
désolé pour l'importation que j'ai essayé tellement de divers chose pour le faire fonctionner....l'étape sont les suivantes : après avoir cliqué sur le bouton poussoir, le programme obtenir la connexion dans le fichier 'File/toCheck.txt" le format est e-mail:la passe et le login sont à envoyer à l'qtreah. Dans le fil de connexion sont essayé avec imap et si la connexion est ok, le QtextEdit imprimer la connexion valide . si vous essayez avec 2-3 e-mail:col en u de fichiers n'ont pas le temps de le voir ne pas fonctionner correctement, mais si vous essayez avec beaucoup de l'interface graphique de gel et le QtextEdit imprimer uniquement lorsque vous avez terminé
Le nombre de threads que vous créez dans cette boucle? Le Python GIL empêche les threads de s'exécuter simultanément, et il est possible que le fait d'avoir un grand nombre de threads est juste de réduire le temps passé dans le thread principal (redessiner l'interface graphique), au point où il semble qu'il soit congelé et pas de mise à jour.
dans ce code, je l'ai envoyer 1 thread par ligne dans le fichier .txt . Mais il peut y avoir 2, 10, 100 ou 1000 le gui de gel de toute façon . J'ai d'abord essayer de faire la même chose avec python fil et de la file d'attente, mais j'émets les mêmes problèmes qu'avec Qthread . L'interface graphique de gel, même si le signal est d'émettre et de l'interface de mise à jour uniquement lors de la finition. Plz me dire ce que je fais mal .
Je recommande découlant Vérificateur de fil de QObject et la création d'un QThread objet, et le vérificateur.moveTo(thread).
désolé pour l'importation que j'ai essayé tellement de divers chose pour le faire fonctionner....l'étape sont les suivantes : après avoir cliqué sur le bouton poussoir, le programme obtenir la connexion dans le fichier 'File/toCheck.txt" le format est e-mail:la passe et le login sont à envoyer à l'qtreah. Dans le fil de connexion sont essayé avec imap et si la connexion est ok, le QtextEdit imprimer la connexion valide . si vous essayez avec 2-3 e-mail:col en u de fichiers n'ont pas le temps de le voir ne pas fonctionner correctement, mais si vous essayez avec beaucoup de l'interface graphique de gel et le QtextEdit imprimer uniquement lorsque vous avez terminé
Le nombre de threads que vous créez dans cette boucle? Le Python GIL empêche les threads de s'exécuter simultanément, et il est possible que le fait d'avoir un grand nombre de threads est juste de réduire le temps passé dans le thread principal (redessiner l'interface graphique), au point où il semble qu'il soit congelé et pas de mise à jour.
dans ce code, je l'ai envoyer 1 thread par ligne dans le fichier .txt . Mais il peut y avoir 2, 10, 100 ou 1000 le gui de gel de toute façon . J'ai d'abord essayer de faire la même chose avec python fil et de la file d'attente, mais j'émets les mêmes problèmes qu'avec Qthread . L'interface graphique de gel, même si le signal est d'émettre et de l'interface de mise à jour uniquement lors de la finition. Plz me dire ce que je fais mal .
Je recommande découlant Vérificateur de fil de QObject et la création d'un QThread objet, et le vérificateur.moveTo(thread).
OriginalL'auteur kenjii himura | 2017-01-07
Vous devez vous connecter pour publier un commentaire.
Car il y a souvent des questions sur l'utilisation de
QThread
en PyQt, semblable à la vôtre, voici un exemple qui montre comment utiliser correctement les threads en PyQt. J'espère que cela peut être utile comme un goto-réponse pour des questions similaires, j'ai donc passé un peu plus de temps que d'habitude à la préparation de ce.L'exemple crée un certain nombre de travailleurs, des objets qui s'exécutent dans la non-threads principaux et de communiquer avec le principal (c'est à dire GUI) fil via Qt asynchrone de signaux.
Les principaux concepts nécessaires pour comprendre multi-thread de programmation en PyQt sont les suivantes:
QThread
, et sa boucle d'événement est géré par le thread.processEvents()
sur leQApplication
instance. Cela permettra à la QThread pour traiter les événements, et donc à appeler des fentes en réponse à des signaux asynchrones à partir de l'interface graphique. Notez queQApplication.instance().processEvents()
semble appelerprocessEvents()
sur chaque fil, si ce n'est pas souhaitée, puisQThread.currentThread().processEvents()
est une alternative valable.QThread.quit()
n'a pas immédiatement quitter sa boucle d'événements: il faut attendre pour en cours d'exécution logement (le cas échéant) de retour. Donc une fois qu'un thread est dit de cesser de fumer, vous devez attendre() sur celui-ci. Donc l'abandon d'un thread de travail implique généralement de signalisation (par l'intermédiaire d'un signal personnalisé) pour arrêter tout ce qu'elle fait: cela nécessite un signal personnalisé sur un objet graphique, une connexion de ce signal à un travailleur de la fente, et le travailleur méthode de travail doit appeler du threadprocessEvents()
pour permettre le signal émis pour atteindre le logement pendant les travaux.Quelqu'un a compris pourquoi cet exemple se bloque si vous essayez d'exécuter les threads de nouveau après son achèvement?
J'nom Freddy McThread, dieu de PyQt fils ! Sérieusement, merci pour la vaste exemple, c'est juste ce dont j'avais besoin.
Zach, le problème est que dans la deuxième manche, le start_threads méthode perd la référence à la liste précédente de threads lorsqu'il appelle l'auto.__threads = []. La solution pour cela est de créer la liste vide que si elle n'a rien stockées précédemment: si pas de soi.__threads: self.__threads = []
Après le fils de finition de 100 étapes, le fils de l'événement, les boucles sont toujours en cours d'exécution. Alors que Sergio dit,
self.__threads = []
rend les fils se ordures collectées, qui obtient une erreur si les fils sont toujours en cours d'exécution. Si vous voulez à la fin de ces fils, de sorte que vous pouvez GC, vous devez appelerthread.quit()
etthread.wait()
sur eux; par exemple, vous pouvez le faire à la fin deon_worker_done()
. Si vous voulez juste ajouter 5 à plus de threads à côté de celles déjà existantes, alors la seule solution est que Sergio proposé.OriginalL'auteur Oliver
Je ne peux pas tester car setimap n'est pas disponible sur mon système. J'ai renommé
CheckerThread
àChecker
puisqu'il n'est plus un thread (c'est juste "vit" dans un thread):Puis il suffit de remplacer le contenu de la boucle dans
gogogo(self)
:C'est presque toujours une bonne idée pour décorer les fentes avec
pyqtSlot
de sorte que les deuxrun
etcheckedok
devrait donc être décoré.La AFIN de répondre à propos de Qt fils est très pratique pour vous rappeler de détails (à noter toutefois qu'elle utilise l'ancien style de connexions-que vous avez à traduire en C++
connect( sender, SIGNAL(sig), receiver, SLOT(slot));
à PyQt5sender.sig.connect(receiver.slot)
).Permettez-moi de savoir si la réponse peut être amélioré pour upvote.
il semble que le travail, mais j'obtiens toujours une erreur que je ne peux pas gérer, maintenant l'erreur est : "pyqt qthread détruits tandis que le thread est toujours en cours d'exécution"
Dans le fichier fonc il y a un jeu avec imap comme : setimap = ["oultook.com:imap-mail.outlook.com", "gmail.com:imap.gmail.com"]
J'ai mis à jour ma réponse, bien que sans voir votre code, il est difficile de dire quel est le problème est, et, évidemment, je ne peux pas l'exécuter parce que les fichiers n'existent pas. Je vous recommande de créer une nouvelle question et après un exemple qui fonctionne en standalone (pas de création de fichier, faites-le en mémoire). Une fois que cela fonctionne, je peux modifier cette réponse si vous pouvez fermer cette question.
OriginalL'auteur Oliver
Désolé pour la réponse tardive mais c'est une technique qui permet de résoudre des problèmes similaires.
Le problème est clair. Le GUI se fige parce que son thread a pour faire un autre travail.
Une abstraction(à partir de la PyQt point) la solution est donnée ci-dessous:
Exemple De Code:
auto.minuterie.délai d'attente.connectez enregistre la fonction de callback.
Bien que simple, cette ad-hoc solution n'a absolument pas se comporte comme prévu dans le cas général. Le fait que c'est un euphémisme fonctionne à tous est un testament à la thread-safe
queue.Queue
classe. La plupart des standards de Python, les classes et les objets sont pas thread-safe; cela comprend la primitive scalaires (par exemple,bool
,int
,str
). Multithread Qt applications tirant parti du faible niveau de Python primitives plutôt que de haut-niveau Qt abstractions (par exemple,QThread
,QConcurrent
) sont absolument de faire le mal. au Lieu de cela, vous devez vous toujours utiliser des connexions signal-slot surQObject
travailleurs déplacés dans unQThread
.OriginalL'auteur Vaggos Phl