QT的事件机制 (5)

QT的事件机制


1、QT的事件机制。

事件(event)是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件是****用户操作做出响应时发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件。

在前面我们也曾经简单提到,Qt 程序需要在main()函数创建一个QApplication对象,然后调用它的exec()函数。这个函数就是开始 Qt 的事件循环。在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件。当事件发生时,Qt 将创建一个事件对象。Qt 中所有事件类都继承于QEvent。在事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler)。

2、QT事件的整体流程。

如图所示:
在这里插入图片描述
app.exe()--------->事件过滤器----->事件分发器-----------------》事件处理函数

下面依次从下往上介绍。

1、事件处理函数。

1、鼠标按下与鼠标释放事件。

提升一个按钮。重写鼠标按下与鼠标释放事件。
mybutton.h

#include <QWidget>
#include <QPushButton>
#include <QMouseEvent>
#include <QEvent>
class MyButton : public QPushButton
{
    Q_OBJECT
public:
    explicit MyButton(QWidget *parent = nullptr);
    //鼠标点击事件
    void mousePressEvent(QMouseEvent *ev);
    //鼠标释放事件
    void mouseReleaseEvent(QMouseEvent *ev);
signals:
};

mybutton.cpp

#include "mybutton.h"
#include <QDebug>

MyButton::MyButton(QWidget *parent)
    : QPushButton{parent}
{

}

void MyButton::mousePressEvent(QMouseEvent *ev)
{
    qDebug() << "鼠标按下" ;
}
void MyButton::mouseReleaseEvent(QMouseEvent *ev)
{
    qDebug() << "鼠标抬起" ;
}

结果如下:
在这里插入图片描述
注意:按钮是提升自定义mybutton类。而mybutton又是继承于QPushButton

2、事件的接收与忽略(accept()和ignore()函数)。

mybutton.h

#include <QWidget>
#include <QPushButton>
#include <QMouseEvent>
#include <QEvent>

class MyButton : public QPushButton
{
    Q_OBJECT
public:
    explicit MyButton(QWidget *parent = nullptr);
    //鼠标点击事件
    void mousePressEvent(QMouseEvent *ev);

signals:

};

mybutton.cpp

#include "mybutton.h"
#include <QDebug>

MyButton::MyButton(QWidget *parent)
    : QPushButton{parent}
{

}

void MyButton::mousePressEvent(QMouseEvent *ev)
{
    if(ev->button() == Qt::LeftButton)
    {
        qDebug() << "MyButton鼠标按下的是左键";
        ev->accept(); // accept 事件不会再往下传递
    }
    else // 鼠标的右键按下与鼠标的中间按键往下传递
    {
        qDebug() << "MyButton鼠标其他键按下";
        QPushButton::mousePressEvent(ev);
    }
}

myWidget.h

#include <QWidget>\
class MyWidget : public QWidget
{
    Q_OBJECT

public:
    MyWidget(QWidget *parent = nullptr);
    ~MyWidget();
    //鼠标点击事件
    void mousePressEvent(QMouseEvent *ev);
private:
    Ui::MyWidget *ui;
};

myWidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"

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

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

void MyWidget::mousePressEvent(QMouseEvent *ev)
{
    if(ev->button() == Qt::LeftButton)
    {
        qDebug() << "MyWidget鼠标左键按下";
    }else {
        qDebug() << "MyWidget鼠标其他键按下";
    }
}

在myWidget类与mybutton类都有重写鼠标事件。
现在accept()函数
当鼠标的左键按下时的打印:
在这里插入图片描述
对鼠标的左键按下不在往下发所以myWidget收不到
当鼠标的右键按下时的打印:
在这里插入图片描述
对鼠标的右键按下往下发所以myWidget能收到

当代码把accept()函数改成ignore()函数。鼠标左键按下事件继续往下传递。传递给了父组件mywidget

void MyButton::mousePressEvent(QMouseEvent *ev)
{
    if(ev->button() == Qt::LeftButton)
    {
        qDebug() << "MyWidget鼠标左键按下";

        ev->ignore(); //忽略,事件继续往下传递,给谁传递?
        //事件传递给了父组件,不是给父类(基类)
    }
    else // 鼠标的右键按下与鼠标的中间按键往下传递
    {
        qDebug() << "MyButton鼠标其他键按下";
        QPushButton::mousePressEvent(ev);
    }
}

以上就是事件的接收与忽略。就是accept()函数与ignore()函数。

2.事件的分发enevt()

1、事件分发的dome。

函数原型: bool event(QEvent *ev)
event()函数主要用于事件的分发。所以,如果你希望在事件分发之前做一些操作,就可以重写这个event()函数了。
myWidget.h

#include <QWidget>
class MyWidget : public QWidget
{
    Q_OBJECT

public:
    MyWidget(QWidget *parent = nullptr);
    ~MyWidget();
    bool event(QEvent *ev);     // 重写event事件
    void keyPressEvent(QKeyEvent *event); //键盘按下事件
    void keyReleaseEvent(QKeyEvent *event);
private:
    Ui::MyWidget *ui;
};

myWidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"

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

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

bool MyWidget::event(QEvent *e)
{
    if(e->type() == QEvent::KeyPress) /* 按键按下的分发 */
    {
        /* 类型转换 */
        QKeyEvent *env = static_cast<QKeyEvent *>(e);
        if(env->key() == Qt::Key_0)
        {
            qDebug() << "event Qt::Key_0";
            return QWidget::event(e); /* 只处理按键0 */
        }
        return true; /* 其他按键不分发下去 */
    } else {
        return QWidget::event(e); /* 其他的事件都分发下去 */
    }
}

void MyWidget::keyPressEvent(QKeyEvent *event) //键盘按下事件
{
    switch(event->key()) {
    case Qt::Key_0:
        qDebug() <<"Qt::Key_0";
        break;
    case Qt::Key_1:
        qDebug() <<"Qt::Key_1";
        break;
    }
}

void MyWidget::keyReleaseEvent(QKeyEvent *event)
{
    qDebug() <<"MyWidget::keyReleaseEvent";
}

总结:当按下按键0按下才处理。其他按键不起作用。
按键0按下的结果:
在这里插入图片描述
其他按键按下不起作用。只打印按键释放。因为如上return QWidget::event(e); /* 其他的事件都分发下去 */
按键是否是可以打印的。如果改成return true; 就不会打印按键释放。

2、enevt事件的缺点。

在这里插入图片描述
从而引出事件过滤器。
在这里插入图片描述
在这里插入图片描述

3、事件的过滤器。

函数原型如下:virtual bool QObject::eventFilter ( QObject * watched, QEvent * event )
watched:过滤哪个控件 event:过滤哪个事件。

这个函数正如其名字显示的那样,是一个“事件过滤器”。所谓事件过滤器,可以理解成一种过滤代码。事件过滤器会检查接收到的事件。如果这个事件是我们感兴趣的类型,就进行我们自己的处理;如果不是,就继续转发。这个函数返回一个 bool 类型,如果你想将参数 event 过滤出来,比如,**不想让它继续转发,就返回 true,否则返回 false。**事件过滤器的调用时间是目标对象(也就是参数里面的watched对象)接收到事件对象之前。也就是说,如果你在事件过滤器中停止了某个事件,那么,watched对象以及以后所有的事件过滤器根本不会知道这么一个事件。
mybutton.h

#include <QPushButton>
class MyButton : public QPushButton
{
    Q_OBJECT
public:
    explicit MyButton(QWidget *parent = nullptr);
    void mouseMoveEvent(QMouseEvent *ev);
signals:

};

mybutton.cpp

#include "mybutton.h"
#include <QDebug>

MyButton::MyButton(QWidget *parent)
    : QPushButton{parent}
{

}
void MyButton::mouseMoveEvent(QMouseEvent *ev)
{
    qDebug() << "mouseMoveEvent";
    QPushButton::mousePressEvent(ev);
}

mywidget.h

#include <QWidget>
class MyWidget : public QWidget
{
    Q_OBJECT
public:
    MyWidget(QWidget *parent = nullptr);
    ~MyWidget();
    //事件过滤器
    bool eventFilter(QObject *obj, QEvent *e);
private:
    Ui::MyWidget *ui;
};

mywidget.cpp

#include "mywidget.h"
#include "ui_mywidget.h"

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    //安装过滤器
    ui->pushButton->installEventFilter(this);
    ui->pushButton->setMouseTracking(true);/* 按钮追踪 */
}

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

bool MyWidget::eventFilter(QObject *obj, QEvent *e)
{
    if(obj == ui->pushButton)
    {
        QMouseEvent *env = static_cast<QMouseEvent *>(e);
        //判断事件

        if(e->type() == QEvent::MouseMove)
        {
            ui->pushButton->setText(QString("eventFilter:(%1, %2)").arg(env->x()).arg(env->y()));
            return true; /* 不分发 */
        }
        else
        {
            return QWidget::eventFilter(obj, e);
        }
        return true;
    }
    else
    {
        return QWidget::eventFilter(obj, e);
    }
}

如上 return true; /* 不分发 */ 所以 qDebug() << “mouseMoveEvent”;没有打印
如果设置return false; 事件不会过滤。就会打印mouseMoveEvent
总结:
在这里插入图片描述

3、总结

现在我们可以总结一下 Qt 的事件处理,实际上是有五个层次:
在这里插入图片描述
上面1, 2,3,点用的多。4, 5不怎么用。
事件过滤器与enevt事件,以及事件的处理函数都是虚函数继承与上层父类。我们在重写时虚函数必须继承上层父类一致。否则就不叫重写。

以上就是今天要讲的内容,QT的事件。主要理解QT从上到下的流程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值