Search code examples
qtqeventqt-events

Qt postEvent() and event filter


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.


Solution

  • 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