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()函数,函数的返回类型为布尔类型。
- 如果传入的事件已被识别并处理,则需要返回true,佛则返回false,如果返回值是true,QT会认为这个事件已经处理完毕,不会再将这个事件发送给其他对象,而是继续处理事件队列中的下一事件
- 在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 *类型,该形式固定,