2017-10-10 6 views
1

J'ai écrit un programme graphique dans PyQt sous Windows. Il y a des opérations coûteuses dans mon programme. Pendant que ces opérations sont en cours, le programme affiche "Ne répond pas" dans la barre de programme.QThread Windows ne répond pas

Je pense que cela doit être cette opération bloquer le thread principal pour mettre à jour l'interface utilisateur, donc j'écris du code multi-threading par QThread pour le tester, il n'a toujours pas de sens.

j'ai écrit un petit programme pour le tester, l'opération n'a pas couru dans le nouveau fil à tous, voici mon petit code de test:

 
from PyQt5.QtCore import QThread, QObject, QCoreApplication, qDebug, QTimer 


class Worker(QObject): 
    def on_timeout(self): 
     qDebug('Worker.on_timeout get called from: %s' % hex(int(QThread.currentThreadId()))) 


if __name__ == '__main__': 
    import sys 

    app = QCoreApplication(sys.argv) 
    qDebug('From main thread: %s' % hex(int(QThread.currentThreadId()))) 
    t = QThread() 
    qDebug(t) 
    worker = Worker() 
    timer = QTimer() 
    timer.timeout.connect(worker.on_timeout) 
    timer.start(1000) 
    timer.moveToThread(t) 
    worker.moveToThread(t) 
    t.start() 

    app.exec_() 

Voici la sortie:

 
From main thread: 0x634 
Worker.on_timeout get called from: 0x634 
+0

Avez-vous essayé ma réponse? Si vous l'avez trouvé utile, veuillez le marquer comme accepté (c.-à-d. Cliquer sur le symbole de la coche). – ekhumoro

Répondre

0

Votre programme a plusieurs erreurs et ne produit pas la sortie que vous montrez.

Premièrement, il n'est pas possible de passer un objet thread à qDebug - l'argument doit être une chaîne. Si vous voulez imprimer des objets, utilisez qDebug(repr(obj)) - ou mieux encore, utilisez print(obj).

Deuxièmement, vous ne pouvez pas démarrer une minuterie en dehors du thread qui l'a créée. Votre exemple établit la connexion de signal dans le thread principal et lance également le temporisateur dans le thread principal. Donc, worker.on_timeout sera appelé dans le fil principal. Mais si vous vous connectez et démarrez le chronomètre après déplacement au thread de travail, vous obtiendrez cette erreur:

QObject::startTimer: Timers can only be used with threads started with QThread

Je pense que l'aide d'une minuterie est inutile, et embrouille votre exemple, il est donc préférable de laisser tout à fait. Au lieu de cela, vous devez connecter le signal started du thread de travail à une méthode run de l'objet worker. Pour simuler une opération de longue durée, vous pouvez utiliser QThread.sleep():

from PyQt5.QtCore import QThread, QObject, QCoreApplication 

class Worker(QObject): 
    def run(self): 
     print('Worker called from: %#x' % int(QThread.currentThreadId())) 
     QThread.sleep(2) 
     print('Finished') 
     QCoreApplication.quit() 

if __name__ == '__main__': 

    import sys 
    app = QCoreApplication(sys.argv) 
    print('From main thread: %#x' % int(QThread.currentThreadId())) 
    t = QThread() 
    worker = Worker() 
    worker.moveToThread(t) 
    t.started.connect(worker.run) 
    t.start() 
    app.exec_() 

Enfin, notez que vous devez toujours effectuer des connexions de signal après le déplacement d'un objet de travailleur à un fil. Les raisons de ceci sont expliquées dans this answer.