Qt 中所有事件类都继承于QEvent。 在事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler),关于这一点,会在后边详细说明。
在所有组件的父类QWidget中,定义了很多事件处理的回调函数,如
这些函数都是 protected virtual 的,也就是说,我们可以在子类中重新实现这些函数。
重写的虚函数要按照它原来的定义的返回值 参数,要完全一样
如果对一些子控件的某一些事件,比如QLabel QpushButton这些。
最好自己构造一个 QLabel或者QpushButton的子类,然后在ui界面设计上把它提升,然后在子类中去写事件处理函数。
下面以QLabel为例,创建一个子类




先到 mylabel.h里面修改

再到mylabel.cpp里面修改
在ui设计界面中添加一个label控件




这是点击了添加之后的窗口



事件处理函数需要完全按照它本身虚函数定义,在子类中重新写一遍 (返回值 函数名 传入参数类型都需要完全一致)
mylabel.h
- #ifndef MYLABEL_H
- #define MYLABEL_H
-
- #include
-
- class Mylabel : public QLabel
- {
- Q_OBJECT
- public:
- explicit Mylabel(QWidget *parent = nullptr);
-
- signals:
-
- // 事件处理函数
- protected:
- void mousePressEvent(QMouseEvent *ev);
- void mouseReleaseEvent(QMouseEvent *ev);
- void mouseMoveEvent(QMouseEvent *ev);
-
- public slots:
- };
-
- #endif // MYLABEL_H
-
mylabel.cpp
- #include "mylabel.h"
- #include
- #include
-
- Mylabel::Mylabel(QWidget *parent) : QLabel(parent)
- {
- // 设置追踪鼠标
- this->setMouseTracking(true);
- }
-
- void Mylabel::mousePressEvent(QMouseEvent *ev)
- {
- int x = ev->x();
- int y = ev->y();
- // 格式化组包
- // QString = str = QString("abc %1 ^_^ %2").arg(123).arg("heqiunong");
- // str = abc 123 ^_^ heqiunong
- QString str = QString("
Mouse Press: (%1, %2)
").arg(x).arg(y); - this->setText(str);
-
- // 鼠标左键按下
- if(ev->button() == Qt::LeftButton)
- {
- qDebug() << "鼠标左键按下";
- }
- // 鼠标右键按下
- else if(ev->button() == Qt::RightButton)
- {
- qDebug() << "鼠标右键按下";
- }
- // 鼠标中键按下
- else if(ev->button() == Qt::MidButton)
- {
- qDebug() << "鼠标中键按下";
- }
-
-
- }
-
- void Mylabel::mouseReleaseEvent(QMouseEvent *ev)
- {
- QString str = QString("
Mouse Release: (%1, %2)
").arg(ev->x()).arg(ev->y()); - this->setText(str);
-
- }
-
- void Mylabel::mouseMoveEvent(QMouseEvent *ev)
- {
- QString str = QString("
Mouse Move: (%1, %2)
").arg(ev->x()).arg(ev->y()); - this->setText(str);
-
-
- }
-
运行结果




widget.h
- #ifndef WIDGET_H
- #define WIDGET_H
-
- #include
-
- QT_BEGIN_NAMESPACE
- namespace Ui { class Widget; }
- QT_END_NAMESPACE
-
- class Widget : public QWidget
- {
- Q_OBJECT
-
- public:
- Widget(QWidget *parent = nullptr);
- ~Widget();
-
- protected:
- // 键盘按下事件
- void keyPressEvent(QKeyEvent *event);
- // 定时器事件
- void timerEvent(QTimerEvent *e);
-
- private:
- Ui::Widget *ui;
- int timer1Id; // 定时器ID
- int timer2Id; // 定时器ID
- };
- #endif // WIDGET_H
-
widget.cpp
- #include "widget.h"
- #include "ui_widget.h"
- #include
- #include
-
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::Widget)
- {
- ui->setupUi(this);
- timer1Id = this->startTimer(1000); // 单位是ms, 1000表示1s产生一次中断
- timer2Id = this->startTimer(100);
- }
-
- Widget::~Widget()
- {
- delete ui;
- }
-
- // 键盘按下事件
- void Widget::keyPressEvent(QKeyEvent *event)
- {
- qDebug() << event->key();
- if(event->key() == Qt::Key_A){
- qDebug() << "Qt::Key_A";
- }
- }
-
- // 定时器事件
- void Widget::timerEvent(QTimerEvent *e){
- // 判断是那个定时器
- if(e->timerId()==this->timer1Id){
- static int sec = 0;
- sec++;
- QString str = QString("
timer1: %1
").arg(sec); - ui->label_2->setText(str);
-
- if(sec >= 10){
- this->killTimer(timer1Id); // 关闭定时器
- QString str = QString("
timer1 is killed
"); - ui->label_2->setText(str);
- }
- }else if(e->timerId()==this->timer2Id){
- static int sec1 = 0;
- sec1++;
- QString str = QString("
timer 2: %1
").arg(sec1); - ui->label_3->setText(str);
- }
- }
-
运行结果:


虽然学qt事件的时候还有其它的内容,比如:事件的接收和忽略、event()、事件过滤器。看看下面这个图了解一些就可以了。
事件的使用方法主要就是上面提到的,自己在子类里面去写特定的事件处理函数。

那么我怎么知道我这个控件,有哪些事件呢?
比如QLabel


比如QWidget


事件函数,有两个特点, ① 前面是virtual, ②函数名称中带有 Event。
我们在代码的时候, 很多时候需要依靠Qt的补全提示功能。比如你在子控件里面重新定义事件处理函数的时候。
但有时候Qt的补全提示功能是失效的,有时候它不提示。
这时候,(难搞,我现在还没搞明白,代码写的不够,后面有体会了再来补充吧)
1、我们可以通过F1找到这个事件处理函数的定义,然后抄过来。
2、或者是,在头文件添加相应的定义。
3、在前面加一下父类的名字
比如 先把void QWidget::写出来,就能弄出来
光写 QWidget::后面的参数带不出来。
4、Ctrl+空格是Qt自动补全的快捷键,容易和输入法切换快捷键冲突
工具->选项->环境->CompleteThis

感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。