Qt: Background thread refreshing UI thread

c++, qt4

Solution

I haven't used `invokeMethod()` myself, but to do this, I usually just use signals and slots. For instance, you could create a signal as a member of `class B` that is connected to the slot in `class A` that updates the progress:

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()` will have to return void in this case but that is not a problem because when using a queued connection, you cannot get a return value anyway since the call is asynchronous (`emit update_signal(true,12)` may return before the slot function is called making it impossible to have a return value ready).

You can actually perform this connection anywhere as long as you have pointers to an object of type `A` and an object of type `B`. This makes the signals and slots very flexible since you could completely decouple `A` from `B`, yet still allow them to communicate through signals and slots. For instance:

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 this case, `b` does not have to store a pointer or know anything about `a` yet they can communicate through a thin well-defined channel.

Problem

I have a background thread and the thread calls some methods that update the UI (in order to show progress bars and show additional info in text areas). If I modify some UI widget values, a "Cannot send events to objects owned by a different thread" assertion error is raised. Looking at forums, I read that I could use QMetaObject::invokeMethod method but it just works if I pass it the Qt::DirectConnection flag that actually raises the same error shown above. If I use Qt::QueuedConnection or Qt::AutoConnection, the invokeMethod returns false. My code looks similar to this: .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. } ``` Do you know what is going on or what i am doing wrong? or maybe, can someone suggest me another approach to deal with my newbie problem? Thanks in advance, Ernesto

Original source