目录
- 1、需求背景
- 2、使用Qt键盘事件
- 3、安装事件过滤器
- 4、事件处理级别
1、需求背景
现在有一个类似于下方图的ui,用户需要在输入前一行内容后,需要摁下指定案件能够跳转到下一行继续进行输入。
2、使用Qt键盘事件
一种更为直接的解决方案是子类化QLineEdit
并且重新实现鼠标事件keyPressEvent()
,然后调用focusNextChild()
。
首先需要创建一个子类MyLineEdit继承于QLineEdit类。然后重写键盘摁下事件。当识别到案件为空格时,就将鼠标焦点切换到下一个。
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Space)
{
focusNextChild();
}
else
{
QLineEdit::keyPressEvent(event);
}
}
然后在ui上将对应的QLineEdit
控件提升为MyLineEdit
类。
运行代码进行测试,效果如下:
这种方法有一个主要的缺点:如果在窗体中使用了好几种不同类型的窗口部件(例如, QComboBox和QSpinBox),我们也必须对它们逐一子类化,以便让它们能够实现相同的行为。一个更好的解决方案是让主窗口监视它的子窗口部件中键的按下事件并且在监视代码中实现所需的行为。这种方法可以通过使用事件过滤器来实现。
3、安装事件过滤器
创建一个事件过滤器包括如下两步过程:
1.通过对目标对象调用installEventFilter()
来注册监视对象。
2.在监视对象的eventFilter()
函数中处理目标对象的事件。
Qt事件模型一个非常强大的功能是:QObject实例在看到它自己的事件之前,可以通过设置另外一个00bject实例先监视这些事件。
在构造函数中注册监视对象
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->lineEdit->installEventFilter(this);
ui->lineEdit_2->installEventFilter(this);
ui->lineEdit_3->installEventFilter(this);
}
这个事件过滤器一旦注册,发送给lineEdit、 lineEdit_2和lineEdit_3窗口部件的事件就会在它们到达目的地之前先被发送给 MainWindow的eventFilter()
函数。
bool MainWindow::eventFilter(QObject *target, QEvent *event)
{
if(target == ui->lineEdit ||
target == ui->lineEdit_2 ||
target == ui->lineEdit_3)
{
if(event->type() == QEvent::KeyPress)
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
qDebug() << "key:" << QString::number(keyEvent->key());
if(keyEvent->key() == Qt::Key_Space)
{
qDebug() << "1";
focusNextChild();
return true;
}
}
}
return QMainWindow::eventFilter(target, event);
}
首先,需要检查一下目标窗口部件是不是QLineEdit
中的一个。如果事件是一个按键事件,那么就把它强制转换为QKeyEvent
并且检查按下的是哪个键。如果按下的键是空格键,那么就调用focusNextChild()
把焦点传递到焦点序列中的下一个窗口部件并且返回true,告诉Qt已经处理了这个事件。如果返回false, Qt将会把这个事件发送给指定的目标对象,而在这个QLineEdit
中产生一个虚假的空格插入操作。
如果窗口部件不是QLineEdit
,或者该事件不是一个空格按键事件,那么就把控制权传递给它的基类的eventFilter()
来执行。这个目标窗口部件也可能是某个基类正在监控的窗口部件。
效果和重写案件事件一样,但是省事很多。
4、事件处理级别
Qt提供了5个级别的事件处理和事件过滤方法。
-
重写控件的事件处理函数:如重写
keyPressEvent()
,mousePressEvent()
和paintEvent()
,这是最常用的事件处理方法。 -
重写
QObject::event()
,在事件到达事件处理函数时处理它。在需要改变Tab键的惯用法时这样做。也可以处理那些没有特定事件处理函数的比较少见的事件类型(例如,QEvent::HoverEnter
)。我们重写event()
时,必须要调用基类的event()
,由基类处理我们不需要处理的那些情况。 -
给QObject对象安装事件过滤器:对象用
installEventFilter()
后,所有达到目标控件的事件都首先到达监视对象的eventFilter()
函数。如果一个对象有多个事件过滤器,过滤器按顺序激活,先到达最近安装的监视对象,最后到达最先安装的监视对象。 -
给
QApplication
安装事件过滤器,如果qApp(唯一的QApplication对象)安装了事件过滤器,程序中所有对象的事件都要送到eventFilter()函数中。这个方法在调试的时候非常有用,在处理非活动状态控件的鼠标事件时这个方法也很常用。 -
继承QApplication,重写
notify()
。Qt调用QApplication::nofity()来发送事件。重写这个函数是在其他事件过滤器处理事件前得到所有事件的唯一方法。通常事件过滤器是最有用的,因为在同一时间,可以有任意数量的事件过滤器,但是notify()函数只有一个。
许多事件类型,包括鼠标,键盘事件,是能够传播的。如果事件在到达目标对象的途中或者由目标对象处理掉,事件处理的过程会重新开始,不同的是这时的目标对象是原目标对象的父控件。这样从父控件再到父控件,知道有控件处理这个事件或者到达了最顶级的那个控件。