QT的Event Filter

原帖出处:

http://www.linuxidc.com/Linux/2011-03/32967.htm


一直对Event Filter似懂非懂, 通过看C++ GUI Programming with Qt4, Second Edition, 争取搞明白. 顺便自己把英文翻译成中文, 算是自己做的笔记了.

Installing Event Filters
QT事件模块一个真正强大的特性是可以设置一个QObject的实例去监测另外一个QObject实例的事件,在被监测的实例see之前.假设我们有一个CustomerInfoDialog这样的widget, 它由几个QLineEdit组成.我们想用Spacer键来转变focus到下一个QLineEdit.这个非标准的行为可能对一个内部的程序很合适, 需要培训它的用户来使用它. 一个直接的方法是子类QLineEdit,然后重新实现keyPressEvent()来调用focusNextChild(), 像这样:

[c-sharp] view plain copy
  1.        void MyLineEdit::keyPressEvent(QKeyEvent *event)  
  2. {  
  3.     if (event->key() == Qt::Key_Space)   
  4.     {  
  5.         focusNextChild();  
  6.     }  
  7.     else  
  8.     {  
  9.         QLineEdit::keyPressEvent(event);  
  10.     }  
  11. }  

这个方法有一个主要的弊端: 如果我们在这个form中用到几个不同类型的widget(比如QComboBox和QSpinBox), 我们必须也子类化它们来表现出相同的行为. 一个更好的方案是让CustomerInfoDialog来监控它的子widget的按键事件,在监测的代码里执行需要的行为. 这可以用event Filter来达到. 设置一个event filter有两个步骤:

1. 在目标对象上调用installEventFilter(),将监测对象注册到目标对象上.
2. 在监测对象的eventFilter()方法里处理目标对象的事件.

在ctor里注册监测对象是一个好地方:

[c-sharp] view plain copy
  1. CustomerInfoDialog::CustomerInfoDialog(QWidget *parent) :QDialog(parent)  
  2.     {  
  3.         ...  
  4.         firstNameEdit->installEventFilter(this);  
  5.         lastNameEdit->installEventFilter(this);  
  6.         cityEdit->installEventFilter(this);  
  7.         phoneNumberEdit->installEventFilter(this);  
  8.     }  


一旦event Filter注册了, 发送到firstNameEdit, lastNameEdit, cityEdit和phoneNumberEdit的事件在被发送到原来的目的地之前, 会先发到CustomerInfoDialog的eventFilter()函数.这是接收这些事件的eventFilter()函数:

[c-sharp] view plain copy
  1. bool CustomerInfoDialog::eventFilter(QObject *target, QEvent *event)  
  2.     {  
  3.         if (target == firstnameEdit || target == lastNameEdit  
  4.             || target == cityEdit || target == phoneNumberEdit)  
  5.         {  
  6.             if(event->type() == QEvent::KeyPress)  
  7.             {  
  8.                 QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);  
  9.                 if (keyEvent->key() == Qt::Key_Space)  
  10.                 {  
  11.                     focusNextChild();  
  12.                     return true;  
  13.                 }  
  14.             }  
  15.         }  
  16.         return QDialog::eventFilter(target, event);  
  17.     }  

首先,我们检查是否目标widget是一个QLineEdit. 如果是个key Press事件, 把它转换为QKeyEvent, 并检查哪个键值被按下.如果是space, 我们调用focusNextChild()把focus传到focus链上的下一个widget上, 返回true告诉Qt我们已经处理了这个事件. 如果我们返回false, Qt会发送这个event到它原来的目的地,导致一个假的空格被插入到QLineEdit.如果目标widget不是QLineEdit, 或者这个event不是一个space按键, 我们把控制权传回到基类的eventFilter去. 目标wdiget可以是基类-QDialog正在监测的某个widget.




Qt提供了5个级别来处理和过滤事件.
1. 我们可以重新实现特定的event handler.
重新实现像mousePressEvent(), keyPressEvent()和paintEvent()这样的event Handler是目前处理event最普通的方式.
2. 我们可以重新实现QObject::event().
通过重新实现event(),我们可以在事件到达特定的event handler之前对它们作出处理. 这个方法主要是用来覆写Tab键的缺省实现. 也可以用来处理不同发生的事件类型,对它们,就没有特定的event handler. 当重新实现event()的时候,我们必须调用基类的event()来处理我们不显式处理的情况.

3. 我们可以安装一个event filter到一个单独的QObject.
一旦一个对象用installEventFilter注册了, 发到目标对象的所有事件都会先发到监测对象的eventFilter(). 如果同一object安装了多个event filter, filter会依次被激活, 从最近安装的回到第一个.
4. 我们可以在QApplication对象上安装event filter.
一旦一个event filter被注册到qApp(唯一的QApplication对象), 程序里发到每个对象的每个事件在发到其他event filter之前,都要首先发到eventFilter(). 这个方法对debugging非常有用. 也可以用来处理发到disable的widget上的事件, QApplication通常会丢弃它们.
5. 我们可以子类QApplication并重新实现notify().
Qt调用QApplication::notify()来发出事件. 在任何event filter得到之前, 重新实现这个函数是得到所有事件的唯一方法. event filter通常更有用, 因为可以有任意数目且同时存在的event filter, 但是只有一个notify()函数.


许多事件类型,包括鼠标和按键事件, 可以被传播. 如果一个事件没有在传到目标对象的过程中被处理,或者被目标对象本身处理, 整个事件处理过程会重复, 不过, 这次, 目标对象的parent作为新的目标对象. 从parent到parent,这样继续下去,知道事件被处理了,或者到达了顶层的对象

在现在的即时聊天程序中,一般都设置有快捷键来实现一些常用的功能,类似QQ可以用CTRL+Enter来实现信息的发送。


在QT4中,所有的事件都继承与QEvent这个类,以下是用QEvent来实现快捷键的功能。


首先所有QT类的基类QObject有一个成员函数installEventFilter,这个函数是用来将一个事件处理器和该QObject绑定起来,所以就有了我下面的想法。


首先在chat类定义一个eventFilter,该函数是一个虚函数,可以由子类进行更改。所以声明eventFilter如下:


virtual bool eventFilter(QObject *obj, QEvent *e);

看了下QT文档对于这个函数的声明的解释,大概意思就是如果你要过滤某个事件就返回false,如果要使用某个事件就返回true。


我想在这个函数中加入对Enter键和Ctrl+Enter组合键的判断,具体查看QKeyEvent类的文档

QKeyEvent类中有函数key和modifier,key函数返回的是发生时间的按键值,modifier返回的而是修饰键,QT所支持的修饰键如下:


Constant                              Value                                             Description

Qt::NoModifier                  0x00000000                                   No modifier key is pressed.

Qt::ShiftModifier                 0x02000000                                  A Shift key on the keyboard is pressed.

Qt::ControlModifier            0x04000000                                  A Ctrl key on the keyboard is pressed.

Qt::AltModifier                   0x08000000                                  An Alt key on the keyboard is pressed.

Qt::MetaModifier   0x10000000                                 A Meta key on the keyboard is pressed.

Qt::KeypadModifier               0x20000000                                 A keypad button is pressed.

Qt::GroupSwitchModifier       0x40000000                                 X11 only. A Mode_switch key on the keyboard is pressed.



所以可以重写eventFilter函数来实现快捷键的功能,可以根据QKeyEvent的key和modifire来分别是Enter还是Ctrl+enter被按下。重写eventFilter的函数如下:


[c-sharp] view plain copy
  1. bool Window::eventFilter(QObject *obj, QEvent *e)  
  2.     {  
  3.         Q_ASSERT(obj == ui.inputMsgEdit);  
  4.         if (e->type() == QEvent::KeyPress)  
  5.         {  
  6.             QKeyEvent *event = static_cast<QKeyEvent*>(e);  
  7.             if (event->key() == Qt::Key_Return && (event->modifiers() & Qt::ControlModifier))  
  8.             {  
  9.                 sendMessage();  
  10.                 return true;  
  11.             }  
  12.         }  
  13.         return false;  
  14.     }  


 


然后把这个过滤器用installEventFilter函数安装在聊天窗口的输入框上(QTextEdit),这样就实现快捷键的功能了。



 



三键组合Shift + Ctrl + A的实现

只要在窗体中相应keyPressEvent事件函数即可。


[c-sharp] view plain copy
  1. void Window::keyPressEvent(QKeyEvent *e)  
  2.     {  
  3.         if (e->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier) && e->key() == Qt::Key_A)  
  4.         {  
  5.             //pressed  
  6.         }  
  7.     }  







键盘按住Ctrl键 + 鼠标左键的实现

在窗体中相应mousePressEvent事件函数在其中检测Ctrl键是否按住即可。


[c-sharp] view plain copy
  1. void Window::mousePressEvent(QMouseEvent *e)  
  2.     {  
  3.         // 获取鼠标在点击窗体上的坐标  
  4.         QPoint pos = e->pos();  
  5.         if (e->button() == LeftButton)  
  6.         {  
  7.             if ( QApplication::keyboardModifiers () == Qt::ControlModifier)  
  8.             {  
  9.                 //pressed  
  10.             }  
  11.         }  
  12.     }  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值