Qt事件研究

Q
QEvent
QEvent类是所有事件类的基类。事件对象包含事件参数。
Qt的主事件循环(QApplication::exec())从事件队列取得本地窗口系统的事件,并将它们转变成QEvent,然后装转换好的事件发送给QObjects。
一般情况下,事件来自底层窗口系统,但是也有可能通过QApplication类的QApplication::sendEvent()和QApplication::postEvent()来手动发送事件。
QObject通过它自己的QObject::event()函数来接收事件。这个函数可以要其子数里重新实现以定义自己的事件处理和新增额外的事件类型。QWidget::event()就是一个典型的例子。默认情况下,事件像QObject::timerEvent()和QWidget::mouseMoveEvent()这样被分派给事件句柄(即事件处理函数)。QObject::installEventFilter()允许一个对像中途截取事件给另外的对象。
基本事件仅包含一个事件类型的参数,QEvent的子类包含附加参数可用来描述特殊的事件。


void QObject::installEventFilter ( const QObject * obj )
安装事件过滤器obj到这个对象。
一个对象上安装的事件过滤器对象能接收所有所有发送到这个对象的事件。(义 译)
Qt中有两种evenfilter,一种是一般的对象的eventfilter一种是application的eventfileter。

QPEApplication::eventFilter和鼠标左键长按变为右键、输入法、contextmenu等有关。
(过滤器对象可以是安装过滤器的对象本身,也可以是其它对象,但不管怎样,过滤器对象都是通过eventFilter()函数来进行事件的过滤操作的,是不是这样的?当然,如果过滤器对象是自己本身的话,也就没有什么意义了)
事件过滤器就是接收所有被发送到这个对象的事件的对象。这个过滤器可以停止事件或者把它再转给这个对象。事件过滤器obj通过它的eventFilter()函数来接收事件。如果事件被过滤了(比如,停止了),eventFilter()函数必须返回真,否则它必须返回假。

如果有多个事件过滤器被安装到同一个对象上,最后一个被安装的事件过滤器将先被激活。

实例:

    #include

    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 ) [虚函数]
如果这个对象已经被安装为watched对象的一个事件过滤器,就过滤事件。
在这个函数你的重新实现中,如果你想过滤出e事件,比如,停止它的进一步处理,返回真,否则返回假。

警告:如果你在这个函数中删除接收对象,请确认返回真。否则,Qt会把这个事件转给被删除的对象并且程序也许会崩溃。


也可以参考installEventFilter()。

在QAccel、QScrollView和QSpinBox中被重新实现。


eventFilter被执行的代码
/*!
  /internal
  Activates all event filters for this object.
  This function is normally called from QObject::event() or QWidget::event().
*/

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,signal本质上是一个callback,是synchronous;
所谓的event一般是通过postEvents()是会进入进程主循环的queue中的,是asynchronous,但是event也可sendEvent()(这种用法是synchronous)
signal的发出者是对象;event的发出者一般来说是窗口系统。
Signals are useful when using a widget, whereas events are useful when implementing a widget. 即在实现一个组件的时候用事件,
例如QButton里
void clicked()是一个信号,它通过keyPressEvent与keyReleaseEvent()来实现。


responsive stay机制
1 当对于要处理一个会消耗时间的事件的时候,如果不做任何处理的话,下面的事件就会马上处理,表现为暂时的假死机。
2 有两种方式可以解决这个问题。之一是use multiple threads在另外一个thread中处理消耗事件的工作。
3 另外一种简单的替代的方式是responsive stay 也就是那些消耗事件的代码一般都是一个循环,在每执行一次的时候调用:qApp->processEvents();
在C++ GUI Programming with Qt 3.chm有一个写文件的例子
for (int row = 0; row < NumRows; ++row) {
        for (int col = 0; col < NumCols; ++col) {
            QString str = formula(row, col);
            if (!str.isEmpty())
                out << (Q_UINT16)row << (Q_UINT16)col << str;
        }
        qApp->processEvents();
    }
 

详细见这个书上的内容
Qtopia2.10中也有用的地方。比如:sysinfor清除一些文件的时候。
(在开机动画中也有一个特殊的用法,这时候app的主循环还没有进入,不过这不属于responsive stay)

你可能感兴趣的:(Qt)