事件(一) 事件的处理

事件(一) 事件的处理

事件的分类

在与用户交互时发生:比如按下鼠标(mousePressEvent),敲击键盘(keyPressEvent)等。
系统自动发生:比如计时器事件(timerEvent)等。
发生事件时(比如说上面说的按下鼠标),就会产生一个QEvent对象(这里是QMouseEvent,为QEvent的子类),这个QEvent对象会传给当前组件的event函数。如果当前组件没有安装事件过滤器(这个下文会提到),则会被event函数发放到相应的xxxEvent函数中(这里是mousePressEvent函数)。
QEvent对象 在这里插入图片描述
在这里插入图片描述
这个QEvent对象会有各种各样的属性,这是由用户与界面交互时产生的。xxxEvent函数可以对其进行不同的处理(比如说是鼠标左键按下还是右键?)。查看帮助文档,可以看到QMouseEvent类有以下枚举。
在这里插入图片描述
那么就可以在mousePressEvent中根据这个QEvent对象的这些枚举值来进行不同的处理,比如

class myLabel : public QLabel
{
protected:
    void mousePressEvent(QMouseEvent *event);
};

void myLabel::mousePressEvent(QMouseEvent *event)
{
    if(event->Buttons == LeftButton)
    {
        //do sth
    }
    else if(event->Buttons == RightButton)
    {
        //do sth
    }
}

可以看到,我们首先需要先创建一个自己的QLabel类,并继承于Qt的QLabel类,然后并重写相应的xxxEvent函数(这些事件处理函数都是虚函数)。


Qt程序的main函数中需要创建一个QApplication对象,然后调用exec函数。这将令程序进入一个死循环,并不断监听应用程序的事件,发生事件时就生成一个QEvent对象。这又称为事件循环。


#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow window;
    window.show();

    return app.exec();
}

事件的分发:event函数

上面提到的xxxEvent函数,称为事件处理器(event handler)。而event函数的作用就在于事件的分发如果想在事件的分发之前就进行一些操作,比如监听某个按键的按下。就在event()中添加相应操作

bool myWidget::event(QEvent *e)
{
//在事件的分发之前就进行一些操作;
    if (e->type() == QEvent::KeyPress) 
    {
       //将QEvent对象转换为真正的QKeyEvent对象
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
        //按键按下
        if (keyEvent->key() == Qt::Key_Tab) 
        {
            qDebug() << "You press tab.";
            return true;
        }
    }
    //按照原来的流程来进行事件的分发
    return QWidget::event(e);
}

在上面的程序中,myWidget是QWidget的子类。同样的,它的event函数是一个虚函数,带有一个QEvent类型的参数。当系统产生QEvent对象时,就会传入这个函数并调用。函数的返回值是bool类型,返回值不同有不同的意义。
在这里插入图片描述


需要注意的是,重写event函数之后最好返回父类的event函数来处理其他的事件分发,不然就只能处理自己定义的事件。

bool myTextEdit::event(QEvent *e)
{
    if (e->type() == QEvent::KeyPress) 
    {
        //将QEvent对象转换为真正的QKeyEvent对象
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
        if (keyEvent->key() == Qt::Key_Tab) 
        {
            qDebug() << "You press tab.";
            return true;
        }
    }
    //直接返回false
    return false;
}

在这个例子中,因为没有调用父类QTextEdit的event函数,所以只能处理Tab的情况,你再按其他按键就啥反应都没有了。同样,事件也不能进行传播。


事件过滤器(Even Filter)

某些应用场景下,需要拦截某个组件发生的事件,让这个事件不再向其他组件进行传播,这时候可以为这个组件或其父组件安装一个事件过滤器(evenFilter)。
QObject有一个虚函数,原型如下

virtual bool QObject::eventFilter ( QObject * watched, QEvent * event );

可以看到,函数有两个参数,一个为具体发生事件的组件,一个为发生的事件(产生的QEvent对象)。当事件是我们感兴趣的类型,可以就地进行处理,并令其不再转发给其他组件。函数的返回值也是bool类型,作用跟even函数类似,返回true为不再转发,false则让其继续被处理。


实际使用中,我们需要对QObject组件调用installEvenFilter函数,即为组件安装过滤器,才能使用事件过滤器这个机制。这样,该组件及其子组件的事件就会被监听。这个机制的好处在于不用像重写QEvent和xxxEvent函数一样需要继承Qt的内置类。

void QObject::installEventFilter ( QObject * filterObj );

下面举一个例子。MainWindow中有一个QTextEdit控件,我们拦截它的键盘按下的事件。这样处理之后,会在输出窗口打印出按下的键位,但不会在控件上显示。这表明事件已被拦截,不会去调用even函数。


class MainWindow : public QMainWindow
{
public:
    MainWindow();
protected:
    bool eventFilter(QObject *obj, QEvent *event);
private:
    QTextEdit *textEdit;
};
 
MainWindow::MainWindow()
{
    textEdit = new QTextEdit;
    setCentralWidget(textEdit);
    
    textEdit->installEventFilter(this);
}
 
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if (obj == textEdit) 
    {
        if (event->type() == QEvent::KeyPress) 
        {
            QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
            qDebug() << "you press" << keyEvent->key();
            //事件不再进行传播,拦截
            return true;
        } 
        else
        {
            return false;//继续传播
        }
    } 
    else 
    {
        //当不确定是否继续传播时,按照父类的方法来处理
        //即调用父类的evenFilter函数
        return QMainWindow::eventFilter(obj, event);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值