2010-07-09 17 views
8

Je simple interface de formulaire qui a une fente pour un bouton, à partir d'un fil: méthodeQThread bloquant l'application principale

void MainWindow::LoadImage() 
{ 
    aThread->run(); 
} 

Et la course() ressemble à ceci:

void CameraThread::run() 
{ 
    qDebug("Staring Thread"); 
    while(1) 
    { 
     qDebug("ping"); 
     QThread::sleep(1); 
    } 
} 

Lorsque Je clique sur le bouton qui appelle LoadImage(), l'interface utilisateur ne répond plus. Je vois périodiquement le message "ping" comme la sortie de débogage, mais l'interface utilisateur se bloque, ne répond à rien. Pourquoi mon thread ne fonctionne pas séparément? CameraThread dérivé comme public QThread J'utilise gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5) avec les librairies QT et QT Creator depuis les dépôts Ubuntu 10.04 (x86).

Répondre

27

Réponse courte: Commencez votre fil en appelant la méthode aThread->start(); pas run(), et assurez-vous enfilez Courons() est protégé (non publique).

Explication

Calling start() is the correct way pour démarrer le fil, car il fournit la planification des priorités et exécute en fait la méthode run() dans son propre contexte de fil.

On dirait que vous allez le chargement des images dans ce fil, donc je vais inclure quelques conseils avant de vous lancer dans les pièges beaucoup de gens tombent dans tout en utilisant QThread

  1. QThread lui-même est pas un fil. Il est juste un emballage autour d'un fil, ce qui nous amène à ..
  2. signaux/slots définis dans la classe CameraThread fonctionneront pas nécessairement dans le contexte du fil, rappelez-vous que la méthode run() et appelé de celui-ci courent dans un fil séparé.

à mon humble avis, le sous-classement QThread dans la majorité des casest pas le chemin à parcourir. Vous pouvez le faire beaucoup plus simple avec le code suivant, et il vous permettra d'économiser de nombreux maux de tête.

class ImageLoader : public QObject { 
Q_OBJECT 
public slots: 
    void doWork() 
    { 
     // do work 
    } 
}; 

void MainWindow::MainWindow(/*params*/) 
{ 
    ImageLoader loader; 
    QThread thread; 
    loader.moveToThread(&thread); 
    connect(this, SIGNAL(loadImage()), &loader ,SLOT(doWork())); 
    thread.start(); 
    // other initialization 
} 
void MainWindow::LoadImage() 
{ 
    emit loadImage(); 
} 

Lisez également le Qt blog concernant ce sujet.

+0

La documentation QT explique l'utilisation de QThread par sous-classe. Pourquoi est-ce une mauvaise idée? –

+1

@Atilla - si vous lisez le lien Blog QT dans la réponse de Casey, vous le trouverez intitulé "Vous vous trompez ...". Il s'agit d'une discussion sur la raison pour laquelle la documentation de Qt sur le sous-classement de QThread n'était pas la bonne façon de faire des threads.En outre, si j'ai lu correctement l'entrée de blog, c'est par la personne qui a écrit la documentation originale de Qt. –

+2

Oui, c'est correct. Fondamentalement, la documentation de Qt est trompeuse et par conséquent a conduit beaucoup de gens à faire des choses hacky (comme movetoThread (this) dans le constructeur Qthread) qui causent des problèmes sur toute la ligne. Espérons que les documents seront mis à jour bientôt. – Casey

4

Vous devez appeler thread-> start() pas exécuté ... run est un point d'entrée pour thread. Le fil commence avec le début. Vous appelez directement run, c'est pourquoi vous bloquez votre gui. Vérifiez la documentation de QThread. vide QThread :: run virtuel() est protégé (non sans raison)

-1

Je pense que le problème pourrait être que vous n'appelez pas QtCore.QThread._init __ (self) dans le constructeur. J'ai eu le même problème. Aussi, je pense que vous ne devriez pas remplacer la fonction de démarrage, juste remplacer la fonction run(). Cela a résolu le même problème que j'avais. Même sans aucun délai de veille(), la fenêtre devrait être réactive.

+1

Non, mon problème appelait run() à la place de début(). J'ai déjà écrasé run(). –