Day02_Qt消息机制与事件 (下)

 1、关于事件

      在之前的程序中已经使用过事件,例如在Qt程序的main()函数中创建一个应用对象QApplication,然后调用它的exec()函数,该exec()函数就是开始Qt的事件循环,在执行exec()函数之后,程序就会进入事件循环来监听应用程序的事件。当事件发生时,Qt将创建一个事件对象,Qt中所有事件都继承于QEvent,在事件对象创建完毕后,Qt将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是根据事件对象的类型分派给特定的事件处理函数(Event handler)。

 

事件处理函数为protected类型,为虚函数,举例:

新建工程,基类为widget,在ui界面中添加label标签:

之后在工程界面添加类文件,由于是添加Label的槽函数,而文件基类中没有Label基类,所以新建的文件基类选为QWidget,之后在生成的mylabel.h与myabel.cpp文件中将基类改为QLabel,.h与.cpp文件如图所示:

#ifndef MYLABEL_H
#define MYLABEL_H

#include <QLabel>

class MyLabel : public QLabel
{
    Q_OBJECT
public:
    explicit MyLabel(QWidget *parent = 0);
protected:
    //鼠标按下事件
    void mousePressEvent(QMouseEvent *ev);
    //鼠标释放事件
    void mouseReleaseEvent(QMouseEvent *ev);
    //鼠标移动事件
    void mouseMoveEvent(QMouseEvent *ev);

     //鼠标进入窗口区域事件
    void enterEvent(QEvent *);
     //鼠标离开窗口区域事件
    void leaveEvent(QEvent *);

signals:

public slots:
};

#endif // MYLABEL_H

mylabel.cpp文件为:

#include "mylabel.h"
#include<QMouseEvent>
#include<QDebug>


MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{

}
//鼠标按下
void MyLabel::mousePressEvent(QMouseEvent *ev)
{
    int i=ev->x();
    int j=ev->y();
    //打印
    if(ev->button() == Qt::LeftButton)
    {
        qDebug() << "left";
    }
    else if(ev->button() == Qt::RightButton)
    {
        qDebug() << "right";
    }
    else if(ev->button() == Qt::MidButton)
    {
        qDebug() << "mid";
    }

    QString text=QString("<center><h1>Mouse Press:(%1,%2)</h1></center>").arg(i).arg(j);

    this->setText(text);

}
//鼠标释放
void MyLabel::mouseReleaseEvent(QMouseEvent *ev)
{
    QString text = QString("<center><h1>Mouse Release: (%1, %2)</h1></center>")
            .arg( ev->x() ).arg( ev->y() );

    this->setText(text);
}

//鼠标移动
void MyLabel::mouseMoveEvent(QMouseEvent *ev)
{
    QString text = QString("<center><h2>Mouse move: (%1, %2)</h2></center>")
            .arg( ev->x() ).arg( ev->y() );

     this->setText(text);
}


void MyLabel::enterEvent(QEvent *ev)
{
    QString text = QString("<center><h1>Mouse enter</h1></center>");

    this->setText(text);
}

void MyLabel::leaveEvent(QEvent *ev)
{
    QString text = QString("<center><h1>Mouse leave</h1></center>");

    this->setText(text);
}

为了使得鼠标在初始时即被跟踪,可以在mylabel.cpp的主函数main函数中添加:

MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{
    //设置追踪鼠标
     this->setMouseTracking(true);
}

之后在ui界面中选择label,将其进行提升,即可看到鼠标在移动、按下....的变化。

2、事件的接收与忽略:

2.1、以一个新的按钮为例,button,在button的槽函数,使用不同的返回语句会有不同的处理效果

当返回语句为

  QPushButton::mousePressEvent(e);

 时,事件会返回到QPushButton的基类中,基类可以发出按键的clicked信号,进而对事件进行处理。处理函数为:

 //信号被上一级拦截,lambda表达式,需要在.pro文件中添加CONFIG +=C++11 

connect(ui->pushButton, &MyButton::clicked, [=]() { qDebug() << "123"; } );

可是采用ignore()作为返回函数时,

e->ignore(); 

事件传递到父组件,不是给父类(基类),所以处理函数是Widget下的处理函数。处理函数为:

void MyWidget::mousePressEvent(QMouseEvent *e)
{
    qDebug() << "+++++++++++++++++++++++";
}

所以,当事件发生后,如果要在事件处理完毕后进行下一级传递,需要将事件继续向下一级件传递,如果下一级的处理函数位于基类中,需要使用基类返回,如果位于父组件中,需要使用ignore()函数。

3、事件event()

        事件对象创建完毕后,Qt会将这个对象传递给Obj的event()函数。event函数并不会直接处理函数,而是将这些事件根据不同的类型,分发给不同的事件处理器(Event Handler)在事件分发处理过程中常常使用到类型转换,如果希望在事件分发之前做一些操作,就可以重新event()函数,函数的返回类型为布尔类型。

  1. 如果传入的事件已被识别并处理,则需要返回true,佛则返回false,如果返回值是true,QT会认为这个事件已经处理完毕,不会再将这个事件发送给其他对象,而是继续处理事件队列中的下一事件
  2. 在event函数中,调用事件对象的accept和ignore是没有作用的,不会影响到事件的传播。我们处理完自己感兴趣的事件之后,可以直接调用父类的event()函数继续转发

在下面的实例程序中,当事件的类型为定时器时,直接返回true代表定时器类型的事件处理完毕,即关闭定时器,如果把定时器部分的注释返回原型,即使得定时器正常工作,之后进行其他事件的处理。

第二个if语句中处理的是按键事件,当按键是按下B时,按照原形式进行,其他形式直接返回true表示事件处理完毕。

bool MyWidget::event(QEvent *e)
{

    if(e->type() == QEvent::Timer)
    {
        //干掉定时器
        //如果返回true,事件停止传播
        //QTimerEvent *env = static_cast<QTimerEvent *>(e);
        //timerEvent(env);
        return true;
    }
    else if(e->type() == QEvent::KeyPress)
    {
        //类型转换
        QKeyEvent *env = static_cast<QKeyEvent *>(e);
        if(env->key() == Qt::Key_B)
        {
            return QWidget::event(e);
        }
        return true;

    }
    else
    {
        return QWidget::event(e);
        //return false;
    }

}

将事件转换为鼠标事件为例:

事件处理器:evenFilter()函数
函数声明:
 //事件过滤器
    bool eventFilter(QObject *obj, QEvent *e);   //过滤的控件----过滤的事件
obj表示要过滤的控件,e表示要进行过滤的事件

//在widget.cpp函数的主函数中添加一下语句方可使用过滤函数
  ui->label_2->installEventFilter(this);

//函数定义

bool MyWidget::eventFilter(QObject *obj, QEvent *e)
{
    if(obj == ui->label_2)
    {
        QMouseEvent *env = static_cast<QMouseEvent *>(e);
        //判断事件
        if(e->type() == QEvent::MouseMove)
        {
            ui->label_2->setText(QString("Mouse move:(%1, %2)").arg(env->x()).arg(env->y()));
            return true;  //不要事件继续传播
        }
        if(e->type() == QEvent::MouseButtonPress)
        {
            ui->label_2->setText(QString("Mouse press:(%1, %2)").arg(env->x()).arg(env->y()));
            return true;
        }
        if(e->type() == QEvent::MouseButtonRelease)
        {
            ui->label_2->setText(QString("Mouse release:(%1, %2)").arg(env->x()).arg(env->y()));
            return true;
        }
        else
        {
            return QWidget::eventFilter(obj, e);
        }
    }
    else
    {
        return QWidget::eventFilter(obj, e);
    }
}
//类型转换
        QKeyEvent *env = static_cast<QKeyEvent *>(e);  
要处理的事件类型为按键事件,所以需要将事件强制转换为 QKeyEvent *类型,该形式固定,
原文地址:https://www.cnblogs.com/luxinshuo/p/12231775.html