Qt中的事件
基本概念:
事件是对各种应用程序需要知道的由应用程序内部或者外部产生的事情或者动作的统称。Qt中使用一个对象来表示一个事件,这个对象继承自QEvent类。事件和信号并非同一概念,在Qt中,任何QObject子类实例都可以接受和处理事件。
qt事件处理过程中发生的传递类似于冒泡,如果在一个窗体内没有设置该事件属性为true,则这个事件就会交给这个窗口的父部件去处理,如果这个事件的属性仍然没有被设置成为true,会继续交给父部件处理,如此往复,一直到最后的基类QEvent或者知道有一个窗口去处理这个事件。
设置事件属性的方式为,调用event->accept(),将其设置为true,不做处理则将event->ignore()设置为false
QEvent
QEvent 是所有事件的基类,事件对象包含事件参数,Qt的主事件循环(QApplication::exec())从事件队列取得本地窗口系统的事件,并且将它们转变成QEvent,然后将转换好的事件发送给QObjects。
1、 一般情况下,事件来自底层窗口系统,但是也有可能通过QApplication类的QApplication::sendEvent()和QApplication::postEvent()来手动发送事件。
2、 QObjects通过它自己的QObject::event()函数来接收事件。这个函数可以要其子数里重新实现以定义自己的事件处理和新增额外的事件类型。QWidget::event()就是一个典型的例子。默认情况下,事件像QObject::timerEvent()和QWidget::mouseMoveEvent()这样被分派给事件句柄(即事件处理函数)。QObject::installEventFilter()允许一个对像中途截取事件给另外的对象。
3、基本事件仅包含一个事件类型的参数,QEvent的子类包含附加参数可用来描述特殊的事件。
相关举例
void QObject::installEventFilter ( const QObject * obj )
安装事件过滤器obj到这个对象,一个对象上安装的事件过滤器对象能接收所有发送到这个对象的事件。事件过滤器就是接收所有被发送到这个对象的事件的对象。这个过滤器可以停止事件或者把它再转给这个对象。事件过滤器obj通过它的eventFilter()函数来接收事件。如果事件被过滤了(比如,停止了),eventFilter()函数必须返回真,否则它必须返回假
如果有多个事件过滤器被安装到同一个对象上,最后一个被安装的事件过滤器将先被激活。举例如下:
#include <qwidget.h>
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget( QWidget *parent = 0, const char *name = 0 );
protected:
bool eventFilter( QObject *, QEvent * );
};
MyWidget::MyWidget( QWidget *parent, const char *name )
: QWidget( parent, name )
{
// 为父对象(如果有的话)安装一个过滤器
if ( parent )
parent->installEventFilter( this );
}
bool MyWidget::eventFilter( QObject *o, QEvent *e )
{
if ( e->type() == QEvent::KeyPress ) {
// 对于键被按下进行特殊处理
QKeyEvent *k = (QKeyEvent *)e;
qDebug( "Ate key press %d", k->key() );
return TRUE; // 吃掉了这个事件
} else {
// 标准事件处理
return QWidget::eventFilter( o, e );
}
}
例如,QAccel类使用这种技术来截取快捷键被按下。
如果在你的eventFilter()函数中你删除了接收对象,请确认返回真。否则,Qt会把这个事件转给被删除的对象并且程序也许会崩溃。
bool QObject::eventFilter ( QObject * watched, QEvent * e ) [虚函数]
注意:如果你想过滤出e事件,比如,停止它的进一步处理,返回真,否则返回假。
警告:如果你在这个函数中删除接收对象,请确认返回真。否则,Qt会把这个事件转给被删除的对象并且程序也许会崩溃。
eventFilter被执行的代码
bool QObject::activate_filters( QEvent *e )
{
if ( !eventFilters ) // no event filter
return FALSE;
QObjectListIt it( *eventFilters );
register QObject *obj = it.current();
while ( obj ) { // send to all filters
++it; // until one returns TRUE
if ( obj->eventFilter(this,e) ) {
return TRUE;
}
obj = it.current();
}
return FALSE; // don't do anything with it
}
signal与event的区别与联系
emit的是一个signal,不是一个event,
所谓的event一般是通过postEvents()是会进入进程主循环的queue中的,是asynchronous,但是event也可sendEvent()(这种用法是synchronous)
signal的发出者是对象;event的发出者一般来说是窗口系统。即在实现一个组件的时候用事件,
例如QButton里,void clicked()是一个信号,它通过keyPressEvent与keyReleaseEvent()来实现
responsive stay机制
1 当对于要处理一个会消耗时间的事件的时候,如果不做任何处理的话,下面的事件就会马上处理,表现为暂时的假死机。
2 有两种方式可以解决这个问题。之一是use multiple threads在另外一个thread中处理消耗事件的工作。
3 另外一种简单的替代的方式是responsive stay 也就是那些消耗事件的代码一般都是一个循环,在每执行一次的时候调用:qApp->processEvents();