2010-03-04 23 views
9

Tengo un hilo de fondo y el hilo llama a algunos métodos que actualizan la interfaz de usuario (para mostrar barras de progreso y mostrar información adicional en áreas de texto).Qt: Hilo de actualización de la interfaz UI hilo

Si modifico algunos valores de widgets UI, se genera un error de aserción "No se puede enviar eventos a objetos propiedad de un hilo diferente".

Al mirar foros, leí que podría usar el método QMetaObject :: invokeMethod, pero solo funciona si le paso el indicador Qt :: DirectConnection que realmente genera el mismo error que se muestra arriba.

Si uso Qt :: QueuedConnection o Qt :: AutoConnection, invokeMethod devuelve falso.

Mi código es similar a esto:

.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. 
} 

¿Conoce lo que está pasando o lo que estoy haciendo mal? o tal vez, ¿alguien puede sugerirme otro enfoque para lidiar con mi problema de novato?

Gracias de antemano,

Ernesto

Respuesta

10

no he usado invokeMethod() mí mismo, pero para hacer esto, por lo general sólo tiene que utilizar señales y slots. Por ejemplo, se podría crear una señal como miembro de class B que se conecta a la ranura en class A que actualiza el progreso:

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() tendrá que volver vacío en este caso, pero eso no es un problema porque cuando utilizando una conexión en cola, no se puede obtener un valor de retorno porque la llamada es asincrónica (emit update_signal(true,12) puede regresar antes de que se llame a la función de ranura, lo que hace imposible tener listo un valor de retorno).

En realidad, puede realizar esta conexión en cualquier lugar siempre que tenga punteros a un objeto de tipo A y un objeto de tipo B. Esto hace que las señales y ranuras sean muy flexibles, ya que podría desacoplar por completo A de B, y aún así permitirles comunicarse a través de señales y ranuras. Por ejemplo:

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

    //... 
} 

En este caso, b no tiene que almacenar un puntero o saber nada de a sin embargo, puede comunicarse a través de un delgado canal bien definido.

Cuestiones relacionadas