Qt事件处理机制

来源:互联网 发布:郑州丰泽教育编程 编辑:程序博客网 时间:2024/05/02 04:20

Qt事件处理机制

一、创建事件QEvent

Qt事件的来源:

-1.系统产生的:通常是window system 把从系统得到的消息,比如鼠标按键等放入系统的消息队列中,Qt事件循环的时候读取这些事件,转化为QEvent.
-2.Qt应用程序自身产生的。

自定义事件

在上述Qt事件来源的第二种方式中,又可分为两种:

-1.Qt预定义的事件
-2.用户自定义事件

用户自定义事件步骤

-1).注册事件ID:
static int QEvent::registerEventType( int hint = -1 ) ;函数返回一个可用的用户事件ID
-2).从QEvent派生出自定义事件,此步骤在调用QEvent构造函数时会使用到第一步注册的ID

二、发送事件

postEvent()

static void QCoreApplication::postEvent( QObject receiver ,QEvent event ,
int priority )
此函数会把事件发送到一个事件队列中

sendEvent()

static bool QCoreApplication::sendEvent( QObject * receiver , QEvent * event)
此函数不会把事件发送到事件队列中

三、事件分发

对于以postEvent()方式发送的事件,会被放入事件队列,然后通过事件循环机制每次从队列中取出一个事件,取出的事件会交给notify()函数,这个函数负责事件的分发。对于以sendEvent()方式发送的事件,不会经历事件循环这个过程,而是直接交由notify()函数进行分发。下面我们来分析notify()实现细节,以下代码是从Qt源码中摘抄的。

bool QCoreApplication::notify(QObject *receiver, QEvent *event){    Q_D(QCoreApplication);    // no events are delivered after ~QCoreApplication() has started    if (QCoreApplicationPrivate::is_app_closing)        return true;    if (receiver == 0) {                        // serious error        qWarning("QCoreApplication::notify: Unexpected null receiver");        return true;    }#ifndef QT_NO_DEBUG    d->checkReceiverThread(receiver);#endif    return receiver->isWidgetType() ? false : d->notify_helper(receiver, event); }
bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event){    // send to all application event filters    if (sendThroughApplicationEventFilters(receiver, event))        return true;    // send to all receiver event filters    if (sendThroughObjectEventFilters(receiver, event))        return true;    // deliver the event    return receiver->event(event);}
bool QObject::event(QEvent *e){    switch (e->type()) {    case QEvent::Timer:        timerEvent((QTimerEvent*)e);        break;#ifdef QT3_SUPPORT    case QEvent::ChildInsertedRequest:        d_func()->sendPendingChildInsertedEvents();        break;#endif    case QEvent::ChildAdded:    case QEvent::ChildPolished:#ifdef QT3_SUPPORT    case QEvent::ChildInserted:#endif    case QEvent::ChildRemoved:        childEvent((QChildEvent*)e);        break;    case QEvent::DeferredDelete:        qDeleteInEventHandler(this);        break;    case QEvent::MetaCall:        {#ifdef QT_JAMBI_BUILD            d_func()->inEventHandler = false;#endif            QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e);            QObjectPrivate::Sender currentSender;            currentSender.sender = const_cast<QObject*>(mce->sender());            currentSender.signal = mce->signalId();            currentSender.ref = 1;            QObjectPrivate::Sender * const previousSender =                QObjectPrivate::setCurrentSender(this, &currentSender);#if defined(QT_NO_EXCEPTIONS)            mce->placeMetaCall(this);#else            QT_TRY {                mce->placeMetaCall(this);            } QT_CATCH(...) {                QObjectPrivate::resetCurrentSender(this, &currentSender,                previousSender);                      QT_RETHROW;            }#endif            QObjectPrivate::resetCurrentSender(this, &currentSender,              previousSender);                                      break;        }    case QEvent::ThreadChange: {        Q_D(QObject);        QThreadData *threadData = d->threadData;        QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher;        if (eventDispatcher) {            QList<QPair<int, int> > timers = eventDispatcher->            registeredTimers(this);            if (!timers.isEmpty()) {                // set inThreadChangeEvent to true to tell the dispatcher not to release out timer ids                // back to the pool (since the timer ids are moving to a new thread).                d->inThreadChangeEvent = true;                eventDispatcher->unregisterTimers(this);                d->inThreadChangeEvent = false;                QMetaObject::invokeMethod(this, "_q_reregisterTimers", Qt::QueuedConnection, Q_ARG(void*, (new QList<QPair<int, int> >(timers))));            }        }        break;    }    default:        if (e->type() >= QEvent::User) {            customEvent(e);            break;        }        return false;    }    return true;}

以上的代码实现细节不需要逐一去理解,只需要搞清楚各个函数的调用关系。首先,notify()函数在最后调用了notify_helper()函数。notify_helper()函数又调用了
return receiver->event(event);event()函数我们可以仔细研究下,其实event()就是根据QEvent的类型对事件进行分派,实现相应事件调用相应的事件处理器。

四、事件处理器

在上面的event()函数中,形如 timerEvent((QTimerEvent*)e);的函数就是事件处理器。在qt中,对Qt事件的使用,最终都是归于对事件处理器的重写。

五、事件处理机制流程图

这里写图片描述
到目前为止,我们已经可以运用Qt提供的事件完成想要实现的功能。使用事件的最基本也是最多的思路是:重载事件处理函数,把要实现的功能以代码的形式写在事件处理函数中。
这种方法可以应付Qt中大多数情况下的应用需求,但是在某些情况下直接重载事件处理器显得过于复杂。对此,Qt提供了事件过滤器。

六、事件过滤器

事件过滤器可以在一个对象处理事件之前调用。
应用事件过滤器很简单,其中只涉及两个函数:installEventFilter()和eventFilter()
如:
-1.A->installEventFilter(B);
-2.重新实现B所对应的类的eventFilter()函数
这就是实现B监视A所需要的全部代码。

原理

对于所有的QObject对象,都有一个QObjectList类型的对象eventFilters,当对一个对象调用installEventFilter时,如:A->installEventFilter(B),此函数会把指向B的指针存入A的eventfilters中。当一个事件发生时,在执行event()之前,Qt会首先检查对象的eventfilters是否为空,若不为空,则对其中指针所指向对象调用eventFilter()函数。函数执行完后,再根据返回值来确定要不要再次执行此事件。若eventFilter()函数返回true,则不会再次执行此事件。否则会继续执行此事件。
下面是Qt源码中installEventFilter()函数的实现:

void QObject::installEventFilter(QObject *obj){    Q_D(QObject);    if (!obj)        return;    if (d->threadData != obj->d_func()->threadData) {        qWarning("QObject::installEventFilter(): Cannot filter events for objects in a different thread.");        return;    }    // clean up unused items in the list    d->eventFilters.removeAll((QObject*)0);    d->eventFilters.removeAll(obj);    d->eventFilters.prepend(obj);}

eventFilter()的优先级

待续。。。。。

1 0
原创粉丝点击