Qt事件系统

4897阅读 0评论2012-08-28 baifengxian
分类:C/C++

                Qt事件系统
摘自:

Qt是事件驱动的, 程序每个动作都是由某个事件所触发。 Qt事件的类型很多,我们可以通过查看Qt的 manual中的Event System 和 QEvent 来获得各个事件的详细信息。

为了完整起见,一份Qt4.6的事件列表附在本文后面。

事件来源

比如考虑重绘事件处理函数 paintEvent(),3种事件都能使得该函数被调用:

事件派发事件循环 while (!exit_was_called) {
while (!posted_event_queue_is_empty) {
process_next_posted_event();
}
while (!spontaneous_event_queue_is_empty) {
process_next_spontaneous_event();
}
while (!posted_event_queue_is_empty) {
process_next_posted_event();
}
}
不通过事件循环

sendEvent的事件派发不通过事件循环。QApplication::sendEvent()是通过调用QApplication::notify(),直接进入了事件的派发和处理环节,是同步的。

sendEvent与postEvent的使用

例子(发送X按键事件到mainWin):

QApplication::postEvent(mainWin, new QKeyEvent(QEvent::KeyPress, Key_X, 'X', 0));

QKeyEvent event(QEvent::KeyPress, Key_X, 'X', 0);
QApplication::sendEvent(mainWin, &event);

notify

所有的事件都最终通过 notify 派发到相应的对象中。

bool QCoreApplication::notify ( QObject * receiver, QEvent * event )事件过滤

看看notify()调用的内部函数notify_helper()的源码部分:

/*!\internal

Helper function called by notify()
*/
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);
}

事件在传递到对象之前(调用obj->event()函数之前),要先能通过 Applicaton 和 obj 安装的过滤器,那么过滤器是怎么安装的:

monitoredObj->installEventFilter(filterObj);

bool QObject::eventFilter ( QObject * watched, QEvent * event )

对于 QCoreApplication ,由于也是QObject 派生类,安装过滤器方式与前述相同。

事件转发

对于某些类别的事件, 如果在整个事件的派发过程结束后还没有被处理, 那么这个事件将会向上转发给它的父widget, 直到最顶层窗口.

如何判断一个事件是否被处理了呢? (有两个层次)

为清楚起见,贴一点Qt的源码(来自 QApplication::notify()):

case QEvent::ToolTip:
case QEvent::WhatsThis:
case QEvent::QueryWhatsThis:
{
QWidget* w = static_cast(receiver);
QHelpEvent *help = static_cast(e);
QPoint relpos = help->pos();
bool eventAccepted = help->isAccepted();
while (w) {
QHelpEvent he(help->type(), relpos, help->globalPos());
he.spont = e->spontaneous();
res = d->notify_helper(w, w == receiver ? help : &he);
e->spont = false;
eventAccepted = (w == receiver ? help : &he)->isAccepted();
if ((res && eventAccepted) || w->isWindow())
break;

relpos += w->pos();
w = w->parentWidget();
}
help->setAccepted(eventAccepted);
}
break;

这儿显示了对 WhatsThis 事件的处理:先派发给 w,如果事件被accepted 或已经是顶级窗口,则停止;否则获取w的父对象,继续派发。

事件处理

QObject与QWidget提供了许多特定的事件handlers,分别对应于不同的事件类型。(如paintEvent()对应paint事件)

event()函数是所有对象事件的入口,QObject和QWidget中缺省的实现是简单地把事件推入特定的事件handlers。

事件过滤器是一个对象,它接收别的对象的事件,在这些事件到达指定目标之间。

事件列表

Qt4.6的事件列表:

上一篇:Qt事件处理机制(下篇)
下一篇:VS2010工程中的*.vcxproj.filters文件