2010-03-04 20 views
9

Ho un thread in background e il thread chiama alcuni metodi che aggiornano l'interfaccia utente (per mostrare le barre di avanzamento e mostrare ulteriori informazioni nelle aree di testo).Qt: thread UI di aggiornamento thread di thread

Se si modificano alcuni valori del widget dell'interfaccia utente, viene generato un errore di asserzione "Impossibile inviare eventi a oggetti di proprietà di un thread diverso".

Guardando i forum, ho letto che potevo usare il metodo QMetaObject :: invokeMethod ma funziona solo se gli passiamo il flag Qt :: DirectConnection che solleva lo stesso errore mostrato sopra.

Se utilizzo Qt :: QueuedConnection o Qt :: AutoConnection, invokeMethod restituisce false.

Il mio codice è simile a questo:

.h:

class A : public QMainWindow 
{ 
    Q_OBJECT 

    QProgressBar* pb; 

    public slots: 
    bool m(bool, int); 
}; 

class B 
{ 
    A* a; 

    public: 
    void handleEvent(); 
}; 


.cpp: 

bool A::m(bool x, int y) 
{ 
    pb->setValue(y); 
    return x; 
} 

void B::handleEvent() 
{ 
    //a->m(true, 12); //raises an assertion error 

    bool r; 
    //bool ret = QMetaObject::invokeMethod(a, "m", Qt::DirectConnection, Q_RETURN_ARG(bool, r), Q_ARG(bool, true), Q_ARG(int, 12)); //raises the same assertion error error 

    bool ret = QMetaObject::invokeMethod(a, "m", Qt::AutoConnection, Q_RETURN_ARG(bool, r), Q_ARG(bool, true), Q_ARG(int, 12)); //is ignored and ret contains false. 
} 

Sai cosa sta succedendo o che cosa sto facendo male? o forse qualcuno può suggerirmi un altro approccio per affrontare il mio problema dei principianti?

Grazie in anticipo,

Ernesto

risposta

10

Non ho usato invokeMethod() me stesso, ma per fare questo, io di solito basta usare segnali e slot. Per esempio, si potrebbe creare un segnale come membro di class B che è collegato allo slot in class A che aggiorna lo stato di avanzamento:

class B : public QObject 
{ 
    Q_OBJECT 

    A* a; 

signals: 
    void update_signal(bool, int); 

public: 
    void handleEvent(); 
}; 

B::B() 
{ 
    //assuming a already points to the correct place... 
    connect(this, SIGNAL(update_signal(bool,int), 
      a, SLOT(m(bool,int)), Qt::QueuedConnection); 
} 

void B::handleEvent() 
{ 
    emit update_signal(true, 12); 
} 

A::m() dovrà restituire void in questo caso, ma che non è un problema perché quando utilizzando una connessione in coda, non è possibile ottenere comunque un valore di ritorno poiché la chiamata è asincrona (emit update_signal(true,12) potrebbe tornare prima che venga richiamata la funzione di slot che rende impossibile avere un valore di ritorno pronto).

È possibile eseguire questa connessione ovunque, purché siano presenti puntatori a un oggetto di tipo A e un oggetto di tipo B. Ciò rende i segnali e le slot molto flessibili, dal momento che è possibile disaccoppiare completamente A da B, e tuttavia consentire loro di comunicare attraverso segnali e slot. Per esempio:

class B : public QObject 
{ 
    Q_OBJECT 

signals: 
    void update_signal(bool, int); 

public: 
    void handleEvent(); 
}; 

void B::handleEvent() 
{ 
    emit update_signal(true, 12); 
} 

class A : public QMainWindow 
{ 
    Q_OBJECT 

    QProgressBar* pb; 

    public slots: 
     void m(bool, int); 
}; 

void A::m(bool x, int y) 
{ 
    pb->setValue(y); 
} 

int main() 
{ 
    A* a = new A(); 
    B* b = new B(); 

    QObject::connect(b, SIGNAL(update_signal(bool, int)), 
      a, SLOT(m(bool, int)), Qt::QueuedConnection); 

    //... 
} 

In questo caso, b non deve memorizzare un puntatore o sapere nulla di a ancora possano comunicare attraverso un sottile canale ben definito.

Problemi correlati