做项目二次开发的时候遇到一个问题,在自己新建的界面中放了很多控件,需要通过键盘方向键来控制焦点在不同控件间的转移,之前用键盘事件检测上下键没有问题,后来加上左右键发现没有反应,查了资料了解到是控件吞掉了左右方向键的信号,因为Qt中本身就有一些处理事件的函数,控件会获取键盘左右方向键的信号,信号被控件获取之后自定义的事件就获取不到了,以下是尝试过的两种方法
解决方法1:直接阻止所有控件获取键盘信号-grabKeyboard()
grabKeyboard()大致功能是阻止控件获取键盘信号,这样自定义键盘事件就能获取到方向键了,直接在构造函数里加上:
this->grabKeyboard();
但是又出现了新的问题,这会导致需要键盘输入的控件例如Line Edit之类的无法输入,于是需要另一个函数 releaseKeyboard()
这个函数的大致功能是释放键盘信号,让控件能够重新获取到键盘信号
在检测到要从键盘向控件输入的时候加上
this->releaseKeyboard();
让控件获取键盘信息,输入结束后立刻grabKeyboard(),这样在自己新建的界面里就没有问题了
然后又发现了问题,我写的代码只是整个项目的一小部分,整个项目有很多界面很多控件,项目运行之后一旦进入我写的界面,grabKeyboard()就会一直生效,直到遇到releaseKeyboard(),而其它界面里是没有releaseKeyboard()的,这就导致其它界面里的输入控件无法输入,直接去改其他界面的代码不太可行,这个方法可能不太适用多人合作的大项目
解决方法2:事件过滤器
这个方法其实在前面方法一之前就试过了,但是因为一个枚举成员没用好导致我以为这个方法不行
在学事件过滤器的时候知道事件过滤器可以截取指定信号,被截取的信号就不会传给控件,所以事件过滤器应该是在控件之前获取信号的
首先在头文件里声明
public slots:
bool eventFilter(QObject *, QEvent *);
然后根据需求定义函数
bool WgDemo::eventFilter(QObject *watched, QEvent *event)
{
if (event->type()==QEvent::KeyPress)
{
qDebug()<<"press";
QKeyEvent *keyevent=static_cast<QKeyEvent *>(event);
if (keyevent->key()==Qt::Key_Right)
{
qDebug()<<"okk";
ui->bit0->setFocus();
}
}
return QObject::eventFilter(watched, event);
}
以下是探索出这个代码的过程和代码分析:
首先需要检测键盘按下的事件
至于为什么是KeyPress而不是Key_Right之类的方向键,我之前的想法是因为方向键获取不到所以我就先检测键盘按下再判断按下的是什么键
我原本的代码是这样的
这样自定义事件依旧没有效果,通过qDebug发现,输出只有press而没有okk,说明第二层if判断右键始终进不去,刚开始就是到这里觉得事件过滤器这个方法不行
后来又去查了参考了各种解决方法之后依葫芦画瓢改
框出来的是最主要的区别,这样的代码就能使自定义事件成功检测到键盘方向键并且不影响控件输入
但是为什么多声明一个QKeyEvent变量就可以了呢
然后研究代码的时候突然发现KeyPress和Key_Right的类名不同,好奇心驱使下把Qt::Key_Right改成了QEvent::Key_Right,然后发现字变黑了
查看QEvent的枚举成员发现并没有Key_Right这个成员,而用于检测信号的参数event是属于QEvent,所以大概是因为Key_Right不存在,导致之前第二个if一直进不去
最后要记得return,事件才能传递下去
然后在构造函数里对每一个需要的控件安装事件过滤器(下面代码只给出其中一个作为例子)
ui->控件名->installEventFilter(this);
ui->B30->installEventFilter(this);