Qt中使用事件过滤器来处理键盘焦点

我们都知道,在主事件循环中,使用QApplication::notify(QObject*, QEvent*)来分发事件到下面的子窗口,而子窗口将调用QObject::event(QEvent*)来根据事件类型调用相应的事件处理函数。在处理键盘焦点的时候,我们把焦点定位特殊部件的习惯通常是Tap键、下一个键盘快捷键或者鼠标滚轮等等,根据传统的方法,为了能够正确切换焦点,我们需要重写每个部件的键盘处理函数,在键盘处理函数中将焦点定位到特定位置,例如在主窗口中有很多的QPushButton按钮,为了使得每次按下一个键盘快捷键的时候能够将焦点切换到下一个QPushButton上,我们需要重写QPushButton的keyPressEvent事件处理函数,如下:


void MyButton::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_Down)
        focusNextChild();
    else
        QPushButton::keyPressEvent(event);  //如果不是按下一个键盘快捷键就直接使用父类QPushButton的该事件处理函数
}

这需要我们继承QPushButton重新构造一个button类。在使用Qt Designer的时候,这种方法似乎不太好用,此时,我们可以使用事件过滤器来处理键盘焦点。


事件过滤器的思想是:让一个对象监听其它对象的时间。假设有对象A和对象B,让对象A来监听对象B的事件,我们且称A为监视器,如果想要A来监视B的事件,我们首先需要在B中注册监视器A,即调用B->installEventFilter(&B),而在监视器A中有一个函数eventFilter(QObject*, QEvent*)专门用来处理A监视到的事件,也就是说,所有被A监视的对象上所发生的事件在送至其目的对象之前都需要先调用监视器中的eventFilter函数。如下一个例子:在一个widget上面有7个QPushButton,我们希望每次按下下一个键盘快捷键的时候能够将焦点定位到下一个QPushButton上,就想平时我们常用的Tab键那样。


思路:


1、首先弄清楚,监视器为widget,被监视者为7个QPushButton;


2、7个QPushButton都需要注册监视器widget;


    ui->pushButton_1->installEventFilter(this);
    ui->pushButton_2->installEventFilter(this);
    ui->pushButton_3->installEventFilter(this);
    ui->pushButton_4->installEventFilter(this);
    ui->pushButton_5->installEventFilter(this);
    ui->pushButton_6->installEventFilter(this);


3、重写监视器widget中的eventFilter来处理监视到的事件;


bool Widget::eventFilter(QObject *target, QEvent *event)
{
    if(target == ui->pushButton_1 || target == ui->pushButton_2 ||
       target == ui->pushButton_3 || target == ui->pushButton_4 ||
       target == ui->pushButton_5 || target == ui->pushButton_6 || target == ui->pushButton_7)
    {
        if(event->type() == QEvent::KeyPress)
        {
            QKeyEvent *keyEvent = static_cast(event);
            if(keyEvent->key() == Qt::Key_0)  //将event转换为QKeyEvent,然后判断是否键
            {
                focusNextChild();
                return true;
            }
        }
    }
    return QWidget::eventFilter(target, event);  //假如并不是7个按钮上的按下下一个键盘快捷键事件,就使用父类的eventFilter
}


所有的代码如下:


widget.h


#ifndef WIDGET_H
#define WIDGET_H

#include 
#include 
#include 

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT
    
public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();
    
protected:
    bool eventFilter(QObject *, QEvent *);

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H


widget.cpp


#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    ui->pushButton_1->installEventFilter(this);
    ui->pushButton_2->installEventFilter(this);
    ui->pushButton_3->installEventFilter(this);
    ui->pushButton_4->installEventFilter(this);
    ui->pushButton_5->installEventFilter(this);
    ui->pushButton_6->installEventFilter(this);
}

bool Widget::eventFilter(QObject *target, QEvent *event)
{
    if(target == ui->pushButton_1 || target == ui->pushButton_2 ||
       target == ui->pushButton_3 || target == ui->pushButton_4 ||
       target == ui->pushButton_5 || target == ui->pushButton_6 || target == ui->pushButton_7)
    {
        if(event->type() == QEvent::KeyPress)
        {
            QKeyEvent *keyEvent = static_cast(event);
            if(keyEvent->key() == Qt::Key_0)  //将event转换为QKeyEvent,然后判断是否键
            {
                focusNextChild();
                return true;
            }
        }
    }
    return QWidget::eventFilter(target, event);  //假如并不是7个按钮上的按下下一个键盘快捷键事件,就使用父类的eventFilter
}

Widget::~Widget()
{
    delete ui;
}


你可能感兴趣的:(qt学习)