2009-07-17 5 views
9

Je suis novice en QT et je fais de l'apprentissage.QT + Comment appeler un emplacement à partir d'un code C++ personnalisé s'exécutant dans un thread différent

Je voudrais déclencher un emplacement qui modifie un widget GUI à partir d'un thread C++ (actuellement un Qthread).

Malheureusement j'ai un: Échec d'ASSERTION à: Q_ASSERT (qApp & & qApp-> thread() == QThread :: currentThread());

ici est un code:

(MAIN + classe Thread)

class mythread : public QThread 
    { 
    public: 
     mythread(mywindow* win){this->w = win;}; 
     mywindow* w; 
     void run() 
     { 
      w->ui.textEdit->append("Hello");  //<--ASSERT FAIL 
      //I have also try to call a slots within mywindow which also fail. 
     }; 
    }; 

    int main(int argc, char *argv[]) 
    { 
     QApplication* a = new QApplication(argc, argv); 
     mywindow* w = new mywindow(); 

     w->show(); 
     mythread* thr = new mythread(w); 
     thr->start(); 

     return a->exec(); 
    } 

fenêtre:

class mywindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    mywindow (QWidget *parent = 0, Qt::WFlags flags = 0); 
    ~mywindow(); 
    Ui::mywindow ui; 

private: 



public slots: 
    void newLog(QString &log); 
}; 

Je suis curieux de savoir comment mettre à jour la partie IUG par le code dans un fil différent.

Merci de nous aider

Répondre

6

En plus de stribika's answer, je trouve souvent plus facile d'utiliser une connexion signal/fente. Vous pouvez spécifier qu'il doit s'agir d'une connexion en file d'attente lorsque vous la connectez, afin d'éviter les problèmes liés aux signaux du thread dans le contexte de son propre objet.

class mythread : public QThread 
{ 
signals: 
    void appendText(QString); 
public: 

    mythread(mywindow* win){this->w = win;}; 
    mywindow* w; 
    void run() 
    { 
     emit (appendText("Hello")); 
    }; 
}; 

int main(int argc, char *argv[]) 
{ 
    QApplication* a = new QApplication(argc, argv); 
    mywindow* w = new mywindow(); 

    w->show(); 
    mythread* thr = new mythread(w); 
    (void)connect(thr, SIGNAL(appendText(QString)), 
        w->ui.textEdit, SLOT(append(QString)), 
        Qt::QueuedConnection); // <-- This option is important! 
    thr->start(); 

    return a->exec(); 
} 
+3

La classe mythread doit contenir la macro Q_OBJECT – CiscoIPPhone

4

Vous devez utiliser QMetaObject::invokeMethod. Par exemple:

void MyThread::run() { 
    QMetaObject::invokeMethod(label, SLOT(setText(const QString &)), Q_ARG(QString, "Hello")); 
} 

(Le code ci-dessus vient d'ici: http://www.qtforum.org/article/26801/qt4-threads-and-widgets.html)

+0

... et c'est faux :) –

+0

@ MarcMutz-mmutz pourriez-vous s'il vous plaît également expliquer ce qui ne va pas avec ce code? Je suppose que c'est la macro SLOT, mais peut-être que vous avez un autre point ;-) – FourtyTwo

+0

'invokeMethod' prend juste le nom de la fonction (' '" setText "' '), pas le résultat de' SLOT'. –

2

Je ne pense pas que vous êtes autorisé à appeler directement les choses qui se traduit par des événements de peinture de toutes autres threads que le thread principal. Cela entraînera un accident.

Je pense que vous pouvez utiliser la boucle d'événements pour appeler les choses de façon asynchrone afin que le thread principal prenne en charge la mise à jour du thread principal, ce que suggère cjhuitt.

11

stribika ont presque droite:

QMetaObject::invokeMethod(textEdit, "append", Qt::QueuedConnection, 
          Q_ARG(QString, myString)); 

droit de cjhuitt, si: Vous voulez généralement de déclarer un signal sur le fil et le connecter à l'emplacement append(), pour obtenir la gestion de la durée de vie des objets gratuitement (bien, pour le prix d'une modification d'interface mineure). Sur un Sidenote, l'argument supplémentaire:

   Qt::QueuedConnection); // <-- This option is important! 

de la réponse de cjhuitt n'est plus nécessaire (il était, dans Qt < = 4.1), étant donné que connect() par défaut Qt::AutoConnection qui maintenant (Qt> = 4.2) fait le droit chose et bascule entre le mode de connexion en attente et direct basé sur QThread::currentThread() et l'affinité de fil du récepteur QObject à émettent temps (au lieu de l'affinité de l'émetteur et du récepteur au moment de la connexion).

+2

Je ne savais pas que la connexion était maintenant à l'heure d'émission ... cela fonctionne-t-il toujours avec les objets threads, qui "vivent" dans le thread où il a été créé, pas le thread est généré lorsque QThread :: run est appelé? (Nous avons juste eu un débat à ce sujet il y a quelques semaines au travail, et j'ai décidé qu'il était plus sûr de spécifier l'option QueuedConnection dans ces cas.) –

+1

J'ai utilisé ceci pour émettre des signaux de Threads qui ne sont pas du tout Qthreads . Fonctionne très bien pour envoyer des événements à la boucle principale de Qt. Aussi, n'a jamais eu à spécifier QueuedConnection avec Qt 4.3 et plus. – Macke

1

Que se passe-t-il si notre affinité de thread indique GUI, mais nous ne sommes pas dans le thread graphique, ni dans un QThread? Ce que je veux dire, c'est qu'un thread non-Qt (notification) appelle la méthode d'interface d'un QObject, dans laquelle nous émettons un signal AutoConnected.L'affinité Thread du QObject est le thread principal, mais la procédure est en fait appelée depuis un autre thread. Que fera le Qt ici?

Questions connexes