Qt postEvent()和事件过滤器

时间:2018-03-28 19:24:18

标签: qt qevent qt-events

我希望在事件循环中实际处理之前,过滤QThread发送给我的工作人员QCoreApplication::postEvent(...)的一些不需要的事件。

什么事件实际上是通过事件过滤器过滤的:调用线程中的postEvent()QThread事件循环中的后期?

我认为答案是"在事件循环"中,但我无法在qt docs中找到对该确切问题的答案。

2 个答案:

答案 0 :(得分:1)

worker和它的事件过滤器都需要存在于同一个线程中。事件由线程的事件循环拾取并在传递到接收器QObject之前通过过滤器(当过滤器允许时)。以下是演示此行为的示例:

#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();
}

输出应该类似于:

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

答案 1 :(得分:1)

必须在事件传递上执行过滤,因为过滤器期望目标对象存在并具有可访问状态。只有在交付事件时才能保证这种存在和状态。从其他线程中使用QObject的方法,保存一些选择是不安全的,因此在发布事件时通常,不可能安全地访问目标对象!。只有在保证对象的生命周期,并且使用线程安全的方法来访问状态时才能这样做,并且它以不会导致死锁的方式完成。