在QT中通过键盘事件过滤,改变QTableWidget的键盘导航行为
2013-09-04 10:57
2351 查看
用QTableWidget做个表格,当单元格在编辑状态的时候,键盘左右方向键是在单元格内移动文本插入点光标。但是我想让左右键结束编辑并直接选中相邻的单元格,效果和上下键一样。也许在高手眼里一点也不困难,不过本人刚接触QT,摸索了两天才解决,期间也有一些心得,所以记下来以免忘记。
QT中所有事件都要先送到qApp,也就是QApplication的实例,从这里再进行分发。分发到哪里呢?对于键盘事件要看当前是谁获得了焦点,这个事件就发给那个对象。如果这个对象处理了事件,那么事件的传递就到此为止;如果这个对象不处理这个事件,事件就会传递给它的父对象,如果父对象也不处理,就继续传给父对象的父对象,直到主窗口为止。
之所以用方向键可以在表格的各单元格间移动,是因为QTableWidget的实例处理了键盘事件。但当有个单元格处于编辑状态的时候,键盘事件就首先分发给单元格里的编辑控件了,这个控件对左右键进行了处理,左右键的事件就不会再传递到QTableWidget的实例了。这个编辑控件的类型是QExpandingLineEdit,怎么知道的呢?这是个内部使用的类,手册上是没有描述的,我在捕获到键盘事件的时候把object->metaObject()->className()打印出来才知道的。
接下来要怎么做呢?
1、给QExpandingLineEdit对象注册事件过滤器?这个不行,给一个对象注册事件过滤器,只对这个对象有效,同一类型的其他对象还是不受影响的。要给表格里的每一个单元格全都注册上过滤器?天啊!
2、创建QExpandingLineEdit的子类并重写事件处理函数?不行,这是个内部使用的类,自己创建的子类没有人用。
3、直接修改QT源代码,在QExpandingLineEdit中实现这个功能,然后重新编译和发布QT库?这样倒是能实现,但是感觉太野蛮了。
4、给QApplication的对象注册过滤器,过滤所有的事件,见到目标对象的类型是QExpandingLineEdit就进行处理?这个看起来可以,下面就按这个思路做。
关于过滤器的返回值,返回false表示事件在过滤器中没有处理,需要继续由目标对象处理。返回true表示在过滤器里已经处理了,目标对象不需要再处理。
关于 sendEvent 与 postEvent:sendEvent 直接将消息发给目标对象,是一个同步操作,因此消息可以从堆栈上分配。postEvent 是将消息入队,待后续再分发处理,因此消息必须在heap上分配,QT系统会在用完后自动释放。
关于判断对象的类型,可以借助QT中的metaObject。不过用C++本身的typeid也可以实现,例如:
后来,我发现在上述代码中用sendEvent重新分发消息还不是最好的,因为这样必须知道表格对象的指针,如果有多个表格的话就更麻烦。更好的做法是使用ignore(),即把qApp->sendEvent(ui.tableWidget,event); 这一行换成event->ignore(); 它表示目标对象将忽略这个事件,这个事件会发给它的父对象。
QT中所有事件都要先送到qApp,也就是QApplication的实例,从这里再进行分发。分发到哪里呢?对于键盘事件要看当前是谁获得了焦点,这个事件就发给那个对象。如果这个对象处理了事件,那么事件的传递就到此为止;如果这个对象不处理这个事件,事件就会传递给它的父对象,如果父对象也不处理,就继续传给父对象的父对象,直到主窗口为止。
之所以用方向键可以在表格的各单元格间移动,是因为QTableWidget的实例处理了键盘事件。但当有个单元格处于编辑状态的时候,键盘事件就首先分发给单元格里的编辑控件了,这个控件对左右键进行了处理,左右键的事件就不会再传递到QTableWidget的实例了。这个编辑控件的类型是QExpandingLineEdit,怎么知道的呢?这是个内部使用的类,手册上是没有描述的,我在捕获到键盘事件的时候把object->metaObject()->className()打印出来才知道的。
接下来要怎么做呢?
1、给QExpandingLineEdit对象注册事件过滤器?这个不行,给一个对象注册事件过滤器,只对这个对象有效,同一类型的其他对象还是不受影响的。要给表格里的每一个单元格全都注册上过滤器?天啊!
2、创建QExpandingLineEdit的子类并重写事件处理函数?不行,这是个内部使用的类,自己创建的子类没有人用。
3、直接修改QT源代码,在QExpandingLineEdit中实现这个功能,然后重新编译和发布QT库?这样倒是能实现,但是感觉太野蛮了。
4、给QApplication的对象注册过滤器,过滤所有的事件,见到目标对象的类型是QExpandingLineEdit就进行处理?这个看起来可以,下面就按这个思路做。
#include "mainwindow.h" #include <QApplication> #include <QKeyEvent> // static_cast 所需要的 #include "ui_mainwindow.h" Ui::MainWindow ui; // 实现过滤器 // 由于 eventFilter() 是QObject的成员函数,因此需要在一个QObject的子类中实现它, // 任何一个QObject都可以,不过这里新建了一个类。 class NavigationKeyFilter:public QObject { bool eventFilter(QObject *object, QEvent *event) { int key; switch(event->type()) { // 只需要过滤按键事件 case QEvent::KeyPress: case QEvent::KeyRelease: // 对QEvent进行强制转换,并获得键值 key = (static_cast<QKeyEvent *>(event))->key(); // 需要过滤的按键 if (key == Qt::Key_Left || key == Qt::Key_Right || key == Qt::Key_Up || key == Qt::Key_Down || key == Qt::Key_Tab) { // 当目标对象的类型是QExpandingLineEdit,则把消息转发给QTableWidget if (! strcmp(object->metaObject()->className(), "QExpandingLineEdit")) { qApp->sendEvent(ui.tableWidget, event); return true; } } default: return false; } return false; } }; int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; ui.setupUi(&w); // 创建过滤器并安装给QApplication NavigationKeyFilter filter; a.installEventFilter(&filter); w.show(); return a.exec(); }
关于过滤器的返回值,返回false表示事件在过滤器中没有处理,需要继续由目标对象处理。返回true表示在过滤器里已经处理了,目标对象不需要再处理。
关于 sendEvent 与 postEvent:sendEvent 直接将消息发给目标对象,是一个同步操作,因此消息可以从堆栈上分配。postEvent 是将消息入队,待后续再分发处理,因此消息必须在heap上分配,QT系统会在用完后自动释放。
关于判断对象的类型,可以借助QT中的metaObject。不过用C++本身的typeid也可以实现,例如:
#include <typeinfo> ...... if (typeid(*object) == typeid(QExpandingLineEdit))
后来,我发现在上述代码中用sendEvent重新分发消息还不是最好的,因为这样必须知道表格对象的指针,如果有多个表格的话就更麻烦。更好的做法是使用ignore(),即把qApp->sendEvent(ui.tableWidget,event); 这一行换成event->ignore(); 它表示目标对象将忽略这个事件,这个事件会发给它的父对象。
相关文章推荐
- Qt 子widget嵌套在父widget里面怎么样捕获键盘事件
- Qt QTableWidget 点击事件 重复问题的解决
- Flex中通过扩展List类重载protected keyDownHandler()事件使键盘导航(keyboard navigation)功能无效的例子
- 谈谈QtWebkit 键盘鼠标事件过滤
- 1.样式表的一些bug, 2.如何通过键盘事件插入spinbox,3.不改变系统编码的前提下,单独转换某一字体编码,4.多色彩颜色失败
- QT QTableWidget中实现整行选中和禁止编辑单元格
- Qt-QTableWidget基本功能(右键菜单)
- QT QTableWidget 用法总结
- QT QTableWidget 用法总结
- Qt 软键盘 [模拟]之键盘触发事件
- jQuery事件--- event.preventDefault() 取消点击动作的默认导航行为
- QT基础(二)----鼠标、键盘事件处理机制、信息拦截机制
- 妙味4:鼠标、键盘事件对象兼容,阻止事件对象的默认行为
- QT QTableWidget 用法总结
- qt QTableWidget&&QTableView 导出数据到excel
- QT QTableWidget 用法总结
- Qt事件获取键盘响应(Ctrl,shift)
- Qt QTableWidget 用法总结
- QT窗口尺寸,窗口大小和大小改变引起的事件 QResizeEvent。
- Qt组件QTablewidget之若干备忘