Qt postEvent() and event filter

2.4k Views Asked by At

I want to filter some unwanted events sent to my worker QThread by QCoreApplication::postEvent(...), before it actually processed in event loop.

When is event actually filtered by event filter: in postEvent() in the calling thread or later in QThread event loop?

I think answer is "in event loop", but i couldn't find answer to that exact question in qt docs.

2

There are 2 best solutions below

0
On BEST ANSWER

Both the worker and its event filter need to be living in the same thread. Events are picked up by the thread's event loop and passed through the filter right before being delivered to their receiver QObject (when the filter allows this). Here is an example that demonstrates this behavior:

#include <QtCore>

//a thread that can be destroyed at any time
//see http://stackoverflow.com/a/25230470
class SafeThread : public QThread{
    using QThread::run;
public:
    explicit SafeThread(QObject *parent = nullptr):QThread(parent){}
    ~SafeThread(){ quit(); wait(); }
};

struct MyEvent : public QEvent {
    static const QEvent::Type myType = static_cast<QEvent::Type>(2000);
    MyEvent():QEvent(myType){}
};

//worker QObject that handles MyEvent by printing a message
class Worker : public QObject {
public:
    explicit Worker(QObject *parent = nullptr):QObject(parent){}
    bool event(QEvent *event) {
        if(event->type() == MyEvent::myType) {
            qInfo() << "event in thread: " << QThread::currentThreadId();
            return true;
        }
        return QObject::event(event);
    }
};

class EventFilter : public QObject {
public:
    explicit EventFilter(QObject *parent = nullptr):QObject(parent){}
    bool eventFilter(QObject *watched, QEvent *event) {
        if(event->type() == MyEvent::myType) {
            qInfo() << "filter in thread: " << QThread::currentThreadId();
            return false; //do not filter the event
        }
        return QObject::eventFilter(watched, event);
    }
};


int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);
    //create worker and thread
    Worker worker;
    EventFilter filter;
    SafeThread thread;
    filter.moveToThread(&thread);
    worker.moveToThread(&thread);
    worker.installEventFilter(&filter);
    thread.start();

    qInfo() << "calling postEvent from thread: " << QThread::currentThreadId();
    QCoreApplication::postEvent(&worker, new MyEvent());

    QTimer::singleShot(1000, &a, &QCoreApplication::quit);
    return a.exec();
}

Output should look something like:

calling postEvent from thread:  0xAAAA
filter in thread:  0xBBBB
event in thread:  0xBBBB
0
On

The filtering must be performed on event delivery, because the filter expects the target object to exist and have an accessible state. Such existence and state can only be guaranteed while the event is being delivered. It is not safe to use QObject's methods, save a select few, from other threads, thus in general when posting an event, it's not possible to safely access the target object!. It's only possible to do so when the object's lifetime is guaranteed, and thread-safe methods are used to access the state, and it's done in a fashion that doesn't lead to deadlocks.