Daily Archives: August 10, 2005

Qt中的事件

Qt中的事件
giscn[at]msn[dot]com
 
1.事件的来源
来源于a)windows系统的事件,经Qt的包装(如QMouseEvent);b)Qt内置的事件(如
QTimerEvent);c)应用程序自定义的事件
 
2.处理事件的位置
2.1 重载虚拟方法
比如一个按钮,要自定义左键click时的行为,可以这样做:
a. 从一个QPushButton上派生一个子类如MyPushButton
b. 重载void MyPushButton::mousePressEvent(QMouseEvent *event)
* 一般来讲,除非要重新改写这个事件的默认行为,否则如果仅是为了扩展其功能,最好在
函数的最后call默认的父类处理方法,如QPushButton::mousePressEvent(event);
* 在调用mousePressEvent这些特定的事件前,先调用通用事件处理函数,QObject::event()
。因此,对于一些特殊情况,我们必须要重定义event(),如我们要对tab键进行重定义。默
认的tab键是将focus移到下一个widget上去。比如在一个text edit widget里,我们可能希
望tab键是向右形成一个置表位置,这时需要在text edit widget的event()进行处理。
2.2 event filter(事件过滤器)方法
一个对象的event filter的处理优先级在 该对象的 event()方法调用之前。这时,filter对
象的eventFilter()方法被调用
* 使用QCoreApplication的事件过滤,可以将任何事件在进行具体对象之前,进行处理。但
需要注意,这可能会使得整个事件处理过程变慢。
  • Reimplementing QCoreApplication::notify. This is very powerful, providing complete control; but only one subclass can be active at a time.
  • Installing an event filter on QCoreApplication::instance(). Such an event filter is able to process all events for all widgets, so it’s just as powerful as reimplementing notify(); furthermore, it’s possible to have more than one application-global event filter. Global event filters even see mouse events for disabled widgets.
  • Reimplementing QObject::event() (as QWidget does). If you do this you get Tab key presses, and you get to see the events before any widget-specific event filters.
  • Installing an event filter on the object. Such an event filter gets all the events except Tab and Shift-Tab key presses.
  • Reimplementing paintEvent(), mousePressEvent() and so on. This is the commonest, easiest and least powerful way.
3. 自定义事件
3.1 自定义事件从QEvent派出,该event number必须大于QEvent::User
3.2 使用postEvent和sendEvent方法派遣自定义事件
* postEvent实质是将事件推进事件循环(event loop),马上返回。事件的实际发送可能在稍
后的一个事件处理时钟内。
* 在某种意义上,程序可以直接调用对象的对应事件函数,而绕过postEvent。但存在不足,
a)很多事件处理函数是protected,意味着你不能直接调用;b)这种直接调用将绕过event
filter;Qt的解决方法是sendEvent。比如repaint()实质是调用了sendEvent。
* sendEvent等待事件被发送成功或失败后才返回。
* postEvent的一个好处是多个posted的event可以被压缩成单一的event,从而提高了效率。
* 可以使用QCoreApplication::sendPostedEvents强迫Qt马上进入事件循环(event loop)派
遣事件。
 
4. 事件的传播(propogation)
如果事件在目标对象上得不到处理,事件向上一层进行传播,直到最顶层的widget为止。
如果得到事件的对象,调用了accept(),则事件停止继续传播;如果调用了ignore(),事件向上一级继续传播。
Qt对自定义事件处理函数的默认返回值是accept(),但默认的事件处理函数是ingore()。因此,如果要继续向上传播,调用QWidget的默认处理函数即可。到时为止的话,不必显式调用accept()。
但在event处理函数里,返回true表示accept,返回false表示向上级传播。
* 在closeEvent是个特殊情形,accept表示quit,ignore表示取消,所以最好在closeEvent显式调用accept和ignore。
 
5. tips
5.1 使用event->type得到事件的具体类型,对之进行判断,是否是需要的类型(比如
KeyPress),然后进行相应处理
5.2 使用static_cast<specific event type *>对通用事件转换成特定类型,比如将event转
成QKeyEvent *,然后调用QKeyEvent::key()取得按下什么键。
5.3 使用sendEvent时,参数 event,必须是局部变量,因为sendEvent不负责对event的删除
。而postEvent的event参数,则必须是 new分配的heap对象,post完了后会自动删除。