1 简介
参考视频:https://www.bilibili.com/video/BV1XW411x7NU?p=31
参考资料:《Qt教程.docx》
本文主要介绍Qt的事件。
2 事件
(1)事件(event)
事件由系统或Qt本身在不同时刻发生的,例如按下鼠标、敲下键盘。
Qt程序需要在main()函数创建一个QApplication对象,然后调用它的exec()函数。这个函数就是开始Qt的事件循环,在执行exec()函数之后,程序将进入事件循环来监听应用程序的事件。但事件发生时,Qt将创建
一个事件对象,Qt中所有事件类都继承QEvent。在事件对象创建完毕后,将这个事件对象传递给QObject的event函数。
event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler)。
(2)事件处理函数
在所有组件的父类QWidget中,定义了很多事件处理的回调函数,这些函数都是 protected virtual 的,也就是说,我们可以在子类中重新实现这些函数。
(3)测试
测试说明:创建一个QLabel,用于显示鼠标按下、释放、移动时的坐标,主要是为了测试鼠标按下、释放、移动这三个事件。
创建一个带ui的QWidget工程:
其中,mylabel是自定义的label,我们重写其鼠标事件:
mylabel.h中的代码如下:
1 #ifndef MYLABEL_H 2 #define MYLABEL_H 3 4 #include <QWidget> 5 #include <QLabel> 6 7 class mylabel : public QLabel 8 { 9 Q_OBJECT 10 public: 11 explicit mylabel(QWidget *parent = nullptr); 12 13 protected: 14 //事件处理函数 15 void mousePressEvent(QMouseEvent *ev); 16 void mouseReleaseEvent(QMouseEvent *ev); 17 void mouseMoveEvent(QMouseEvent *ev); 18 19 signals: 20 21 public slots: 22 }; 23 24 #endif // MYLABEL_H
mylabel.cpp中的代码如下:
1 #include "mylabel.h" 2 #include <QMouseEvent> 3 #include <QString> 4 5 mylabel::mylabel(QWidget *parent) : QLabel(parent) 6 { 7 this->setMouseTracking(true); 8 } 9 10 void mylabel::mousePressEvent(QMouseEvent *ev) 11 { 12 QString text = QString("<center><h1>Mouse press:: (%1, %2)</h1></center>").arg(ev->x()).arg(ev->y()); 13 this->setText(text); 14 } 15 16 void mylabel::mouseReleaseEvent(QMouseEvent *ev) 17 { 18 QString text = QString("<center><h1>Mouse release:: (%1, %2)</h1></center>").arg(ev->x()).arg(ev->y()); 19 this->setText(text); 20 } 21 22 void mylabel::mouseMoveEvent(QMouseEvent *ev) 23 { 24 QString text = QString("<center><h1>Mouse move:: (%1, %2)</h1></center>").arg(ev->x()).arg(ev->y()); 25 this->setText(text); 26 }
上述代码中使用了QWidge的mouseTracking属性,该属性用于设置是否追踪鼠标。只有鼠标被追踪时,mouseMoveEvent()才会发出。如果mouseTracking是 false(默认即是),组件在至少一次鼠标点击之后,才能够被追踪,也就是能够发出mouseMoveEvent()事件。如果mouseTracking为 true,则mouseMoveEvent()直接可以被发出。
将ui中的label提升为我们自定义的label。运行进行测试:
3 event()函数
(1)介绍
事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是将这些事件对象按照它们不同的类型,分发给不同的事件处理器(event handler)。
event()函数主要用于事件的分发。
如果你希望在事件分发之前做一些操作,可以重写这个event()函数。
函数原型:virtual bool event(QEvent *event);
返回值说明:如果传入的事件已被识别并处理,则需要返回true,否则返回false。如果返回值是true,那么Qt会认为这个事件已经处理完毕,不再将这个事件发送给其它对象,而是会继续处理事件队列中的下一个事件。
(2)测试
功能:在event函数中判断主窗口的鼠标移动事件,并将鼠标所在的坐标在QLabel中显示出来。
工程文件有:
在widget.h中声明event函数:
1 #ifndef WIDGET_H 2 #define WIDGET_H 3 4 #include <QWidget> 5 6 namespace Ui { 7 class Widget; 8 } 9 10 class Widget : public QWidget 11 { 12 Q_OBJECT 13 14 public: 15 explicit Widget(QWidget *parent = 0); 16 ~Widget(); 17 18 protected: 19 //事件分发 20 bool event(QEvent *event); 21 22 private: 23 Ui::Widget *ui; 24 }; 25 26 #endif // WIDGET_H
在widget.cpp中实现event函数:
1 #include "widget.h" 2 #include "ui_widget.h" 3 #include <QEvent> 4 #include <QLabel> 5 #include <QString> 6 #include <QMouseEvent> 7 8 Widget::Widget(QWidget *parent) : 9 QWidget(parent), 10 ui(new Ui::Widget) 11 { 12 ui->setupUi(this); 13 this->setMouseTracking(true); 14 } 15 16 bool Widget::event(QEvent *event) 17 { 18 //判断事件是否是鼠标移动 19 if (event->type() == QEvent::MouseMove) { 20 QMouseEvent *ent = static_cast<QMouseEvent *>(event); 21 QString text = QString("<center><h1>Mouse move(%1, %2)</h1></center>").arg(ent->x()).arg(ent->y()); 22 ui->label->setText(text); 23 //返回true,事件停止传播 24 return true; 25 } else{ 26 //其它事件继续传播 27 return QWidget::event(event); 28 } 29 } 30 31 Widget::~Widget() 32 { 33 delete ui; 34 }
运行测试:
(3)总结
event()函数中实际是通过事件处理器来响应一个具体的事件。这相当于event()函数将具体事件的处理“委托”给具体的事件处理器。而这些事件处理器是 protected virtual 的,因此,我们重写了某一个事件处理
器,即可让Qt 调用我们自己实现的版本。
event()是一个集中处理不同类型的事件的地方。如果你不想重写一大堆事件处理器,就可以重写这个event()函数,通过QEvent::type()判断不同的事件。
4 事件过滤器
(1)介绍
有时候对象需要查看、甚至要拦截发送到另外对象的事件,需要用到事件过滤器。事件过滤器与event()、事件处理器的关系如下:
事件过滤器,可以理解成一种过滤代码,它会检查接收到的事件,如果这个事件是我们感兴趣的类型,就进行我们自己的处理;如果不是,就继续转发。
函数原型:virtual bool eventFilter(QObject *watched, QEvent *event);
事件过滤器会检查接收到的事件,如果这个事件是我们感兴趣的类型,就自己处理,否则继续转发。返回值是一个bool类型,如果你想将参数 event 过滤出来,比如,不想让它继续转发,就返回 true,否则返回 false。
(2)测试
功能:创建一个事件过滤器,过滤出label标签中的鼠标移动事件并进行处理。
工程代码:
widget.h中添加eventFilter()函数声明:
1 #ifndef WIDGET_H 2 #define WIDGET_H 3 4 #include <QWidget> 5 6 namespace Ui { 7 class Widget; 8 } 9 10 class Widget : public QWidget 11 { 12 Q_OBJECT 13 14 public: 15 explicit Widget(QWidget *parent = 0); 16 ~Widget(); 17 18 protected: 19 //事件过滤器 20 bool eventFilter(QObject *watched, QEvent *event); 21 22 private: 23 Ui::Widget *ui; 24 }; 25 26 #endif // WIDGET_H
widget.cpp中添加实现eventFileter()函数,并过滤出Label对象的鼠标移动事件。
1 #include "widget.h" 2 #include "ui_widget.h" 3 #include <QLabel> 4 #include <QMouseEvent> 5 #include <QEvent> 6 #include <QString> 7 8 Widget::Widget(QWidget *parent) : 9 QWidget(parent), 10 ui(new Ui::Widget) 11 { 12 ui->setupUi(this); 13 //安装过滤器 14 ui->label->installEventFilter(this); 15 ui->label->setMouseTracking(true); 16 } 17 18 Widget::~Widget() 19 { 20 delete ui; 21 } 22 23 bool Widget::eventFilter(QObject *watched, QEvent *event) 24 { 25 //观察对象为label 26 if (watched == ui->label) { 27 QMouseEvent *ent = static_cast<QMouseEvent *>(event); 28 //判断鼠标移动事件 29 if (event->type() == QEvent::MouseMove) { 30 QString text = QString("<center><h1>mouse move:(%1, %2)</h1></center>").arg(ent->x()).arg(ent->y()); 31 ui->label->setText(text); 32 return true; 33 } 34 } 35 //继续传递事件 36 return QWidget::eventFilter(watched, event); 37 }
运行测试: