2009-07-17 19 views
9

Sono nuovo a QT e sto facendo un po 'di apprendimento.QT + Come chiamare lo slot dal codice C++ personalizzato in esecuzione in un thread diverso

Vorrei attivare uno slot che modifica un widget GUI da un thread C++ (attualmente un Qthread).

Sfortunatamente ottengo un: ASSERZIONE non riuscita a: Q_ASSERT (qApp & & qApp-> thread() == QThread :: currentThread());

Ecco il codice:

(classe thread principale +)

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

Window:

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

Quindi io sono curioso su come aggiornare la parte gui da codice in un filo diverso

Grazie per l'aiuto

risposta

6

Oltre a stribika's answer, spesso trovo più facile da usare una connessione segnale/slot. È possibile specificare che dovrebbe essere una connessione accodata quando la si connette, per evitare problemi con i segnali del thread che si trovano nel contesto del proprio oggetto proprietario.

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 deve contenere la macro Q_OBJECT – CiscoIPPhone

4

è necessario utilizzare QMetaObject::invokeMethod. Ad esempio:

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

(Il codice precedente viene da qui: http://www.qtforum.org/article/26801/qt4-threads-and-widgets.html)

+0

... ed è sbagliato :) –

+0

@ MarcMutz-mmutz potresti spiegare anche cosa c'è di sbagliato in questo codice? Sospetto che sia la macro SLOT, ma potrebbe essere che tu avessi qualche altro punto ;-) – FourtyTwo

+0

'invokeMethod' prende solo il nome della funzione (' '" setText "' '), non il risultato di' SLOT'. –

2

non credo che v'è permesso di chiamare direttamente le cose che si traduce in eventi di vernice da parte di altre le discussioni che il thread principale. Ciò si tradurrà in un incidente.

Penso che sia possibile utilizzare il ciclo degli eventi per chiamare le cose in modo asincrono in modo che il thread dell'interfaccia principale prelevi e poi esegua l'aggiornamento dal thread principale, che è ciò che suggerisce cjhuitt.

11

stribika ottenuto quasi: destro

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

di cjhuitt, però: di solito si vuole dichiarare un segnale sul filo e collegarlo allo slot append(), per ottenere la gestione degli oggetti di vita per libero (beh, per il prezzo di un cambio di interfaccia minore). Su un sidenote, l'ulteriore argomento:

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

dalla risposta di cjhuitt non è più necessario (era, in Qt < = 4.1), dal momento che connect() default Qt::AutoConnection che ora (Qt> = 4.2) fa la destra cosa e passa tra la modalità di connessione in coda e diretta basata su QThread::currentThread() e l'affinità del thread del ricevitore QObject allo emettono il tempo (invece di affinità di mittente e destinatario al momento della connessione).

+2

Non sapevo che la connessione fosse ora in emit time ... funziona ancora con gli oggetti thread, che "vivono" nel thread in cui è stato creato, non il thread che viene generato quando viene chiamato QThread :: run? (Abbiamo appena avuto un dibattito su questo un paio di settimane fa al lavoro, e ho deciso che era più sicuro specificare l'opzione QueuedConnection in questi casi.) –

+1

Ho usato questo per emettere segnali da Thread che non sono Qthreads a tutti . Funziona alla grande per l'invio di eventi al loop principale di Qt. Inoltre, non è mai stato necessario specificare QueuedConnection con Qt 4.3 e versioni successive. – Macke

1

Cosa succede se la nostra affinità di thread dice la GUI, ma non siamo nel thread della GUI, né in un QThread?

Quello che voglio dire è che un thread non-Qt (notifica) chiama un metodo di interfaccia di QObject, nel quale emettiamo un segnale AutoConnected.L'affinità di Thread di QObject è Main thread, ma la procedura viene effettivamente chiamata da un altro thread. Cosa farà il Qt qui?

Problemi correlati