2009-07-17 12 views
9

Ich bin neu in QT und lerne etwas.QT + Wie man Slot aus benutzerdefiniertem C++ - Code aufruft, der in einem anderen Thread läuft

Ich möchte einen Steckplatz auslösen, die ein GUI-Widget aus einem C++ - Thread (derzeit ein Qthread) ändern.

Unfortunatly ich a: Assertionsfehler bei: Q_ASSERT (qApp & & qApp-> Gewinde() == QThread :: current());

hier ist ein Code:

(Klasse Thread MAIN +)

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(); 
    } 

Fenster:

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); 
}; 

So bin ich gespannt, wie in einem der gui Teil von Code zu aktualisieren anderer Thread.

Vielen Dank für

Antwort

6

Neben stribika's answer ich es oft einfacher finden ein Signal/Slot-Verbindung zu verwenden. Sie können angeben, dass es sich bei der Verbindung um eine Verbindung in der Warteschlange handeln soll, um Probleme mit den Signalen des Threads im Kontext des zugehörigen Objekts zu vermeiden.

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

Die mythread-Klasse muss das Q_OBJECT-Makro enthalten – CiscoIPPhone

4

helfen müssen Sie QMetaObject::invokeMethod verwenden. Zum Beispiel:

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

(Der obige Code stammt von hier: http://www.qtforum.org/article/26801/qt4-threads-and-widgets.html)

+0

... und es ist falsch :) –

+0

@ MarcMutz-mmutz Könnten Sie bitte auch erklären, was mit diesem Code falsch ist? Ich vermute, dass es das SLOT-Makro ist, aber vielleicht hast du einen anderen Punkt ;-) – FourtyTwo

+0

'invokeMethod' nimmt nur den Funktionsnamen (' '" setText "' '), nicht das Ergebnis von' SLOT'. –

2

Ich glaube nicht, dass Sie direkt Dinge nennen darf, die von irgendwelchen andere Threads als der Haupt-Thread in Farbe Ereignissen führen. Das wird zu einem Absturz führen.

Ich denke, Sie können die Ereignisschleife verwenden, um Dinge asynchron aufzurufen, so dass der Hauptgui-Thread abholt und dann die Aktualisierung vom Hauptthread ausführt, was cjhuitt vorschlägt.

11

stribika hat es fast richtig:

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

cjhuitt hat Recht, wenn: Sie wollen in der Regel ein Signal auf dem Thread erklären und an den append() Slot zu verbinden, Objektlebensdauer-Management kostenlos (gut zu bekommen, für den Preis einer kleinen Schnittstellenänderung). Auf Nebenbei bemerkt, das zusätzliche Argument:

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

von Antwort cjhuitt der ist nicht mehr notwendig (es war, in Qt < = 4.1), da connect() standardmäßig Qt::AutoConnection das jetzt (Qt> = 4.2) hat das Recht, Sache und schaltet zwischen eingereihten und direkten Verbindungsmodus basierend auf QThread::currentThread() und die Thread-Affinität des Empfängers QObject um emittieren Zeit (anstelle von Sender und Empfänger Affinität zum Zeitpunkt der Verbindung).

+2

Ich wusste nicht, dass die Verbindung jetzt zum Zeitpunkt der Ausgabe war ... funktioniert das immer noch mit Thread-Objekten, die im Thread "lebe", wo es erstellt wurde, nicht der Thread Wird erzeugt, wenn QThread :: run aufgerufen wird? (Wir hatten gerade vor ein paar Wochen eine Diskussion darüber, und entschieden, dass es in diesen Fällen sicherer ist, die QueuedConnection-Option anzugeben.) –

+1

Ich habe das verwendet, um Signale von Threads auszusenden, die überhaupt keine Qthreads sind . Funktioniert hervorragend zum Senden von Ereignissen _to_ Qt's Hauptschleife. Außerdem musste QueuedConnection nie mit Qt 4.3 und höher angegeben werden. – Macke

1

Was ist, wenn unsere Thread-Affinität GUI sagt, aber wir sind nicht im GUI-Thread, noch in einem QThread?

Was ich meine ist, ein non-Qt (Benachrichtigung) -Thread ruft eine QObject-Interface-Methode auf, in der wir ein AutoConnected-Signal ausgeben.Die Thread-Affinität des QObjects ist Haupt-Thread, aber die Prozedur wird tatsächlich von einem anderen Thread aufgerufen. Was macht der Qt hier?

Verwandte Themen