一、事件机制
qt的核心机制:对象树、信号和槽、事件机制
1.1概念
就是当这件事情发生时,自动执行对应的功能代码。该某块功能代码是虚函数,只需重写该虚函数,即可执行重写的代码。
1.2事件处理简介
1. 什么是事件? (重点)
事件是由窗口系统或者自身产生的,用以响应所发生的 各类事情,比如用户按下并释放了键盘或>者鼠标、窗口因 暴露而需要重绘、定时器到时而应有所动作,等等。
从某种意义上讲,事件比信号更原始,甚至可以认为大多 数信号其实都是由事件产生的。比如一个下压式按钮首先 感受到的是鼠标事件, 在进行必要的处理以产生按钮下沉 继而弹起的视觉效果之后,才会发射 clicked()信号。
2. 如何处理事件? (重点)
myWnd(自定义类) -继承-> QWidget -继承-> QObject
1> 当事件发生时,首先被调用的是QObject类中的虚函数event(), 其 QEvent型参数标识了具体的事件类型。
bool QObject:: event (QEvent* e) { if (e == mouseEvent) { void QWidget::mousePressEvent (QMouseEvent* e) void QWidget:: mouseReleaseEvent (QMouseEvent* e) } if(e == keyEvent){ void QWidget::keyPressEvent (QMouseEvent* e) void QWidget:: keyReleaseEvent (QMouseEvent* e) } }
2> 作为QObject类的子类, QWidget类覆盖了其基类中的 event()虚函数,并根据具体事件调用具体事件处理函数
void QWidget::mousePressEvent (QMouseEvent* e) void QWidget::mouseReleaseEvent (QMouseEvent* e) void QWidget::keyPressEvent (QMouseEvent* e) void QWidget:: keyReleaseEvent (QMouseEvent* e) void QWidget::paintEvent (QPaintEvent* e):
3> 而这些事件处理函数同样也是虚函数,也可以被 QWidget类 的子类覆盖,以提供针对不同窗口部件类型的事件处理
4> 组件的使用者所关心的往往是定义什么样的槽处理什么样的信号, 而组件的实现者更关心覆盖哪些事件处理函数
1.3 事件处理函数由来
QObject类 提供了哪些可以重写的虚函数:
[virtual] bool QObject::event(QEvent *e) // 参数:事件的类型
QWidgets类, 提供了哪些可以重写的虚函数:
[override virtual protected] bool QWidget::event(QEvent *event) [virtual protected] void QWidget::keyPressEvent(QKeyEvent *event) [virtual protected] void QWidget::keyReleaseEvent(QKeyEvent *event) [virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event) [virtual protected] void QWidget::mousePressEvent(QMouseEvent *event) [virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event) [virtual protected] void QWidget::mouseDoubleClickEvent(QMouseEvent *event) [virtual protected] void QObject::timerEvent(QTimerEvent *event)
QPainter类 ---> 画家类
void SimpleExampleWidget::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setPen(Qt::blue); painter.setFont(QFont("Arial", 30)); painter.drawText(rect(), Qt::AlignCenter, "Qt"); }
二、定时器事件 QTimerEvent
2.1 作用
让系统每隔一定的时间,自动执行某块功能代码。
2.2 基于事件机制(涉及的函数 )
1、启动定时器
startTimer(int sec); //启动一个定时器,给定毫秒数,返回值是该定时器的id 每隔一定的时间,自动执行timerEvent()函数。
2、关闭定时器
killTimer(int id); //关闭定时器,关闭哪个定时器以id号为准
3、定时器超时
timerEvent(); //定时器超时时,自动执行的功能代码 --->是QWidget提供的虚函数
案例
#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); // id2 = startTimer(2000); } Widget::~Widget() { delete ui; } //定时器超时时,自动执行的功能函数 void Widget::timerEvent(QTimerEvent *e) { //判断哪个定时器超时 if(e->timerId() == id) { // static int num =0; // ui->label->setNum(++num); //获取系统时间 QTime sys_time = QTime::currentTime(); //将时间转换成字符串 QString t = sys_time.toString("hh--mm--ss"); //将系统时间放入lab中 ui->label->setText(t); //文本居中显示 ui->label->setAlignment(Qt::AlignCenter); } } //启动按钮对应的槽函数 void Widget::on_pushButton_clicked() { if(ui->pushButton->text() == "启动") { //启动一个定时器 id = startTimer(1000); //每隔1秒钟,自动执行timerEvent()函数 //将文本设置“关闭” ui->pushButton->setText("关闭"); } else { //关闭定时器 killTimer(id); //将文本设置“启动” ui->pushButton->setText("启动"); } }
2.4 基于属性版本(信号和槽)
- QTime 时间类
- QTimeEvent 定时器事件类
- QTimer 时间事件类
1、使用QTimer类实例化一个对象
2、用该对象调用成员函数 start(int sec); //启动一个定时器,每个一定毫秒,自动触发timeout信号
3、将timeout信号连接到自定的槽函数中
4、用该对象调用成员函数stop(); //关闭定时器
案例
头文件:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include<QTime> //时间类 #include<QTimer> //时间事件类 #include<QTimerEvent> //定时器事件类 QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); //重写timerEvent()函数的声明 void timerEvent(QTimerEvent *e); private slots: void on_pushButton_clicked(); void on_pushButton_2_clicked(); void timeout_slot(); private: Ui::Widget *ui; //定义一个定时器的id int id; // 实例化一个时间事件对象 QTimer *timer; }; #endif // WIDGET_H
源文件:
#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) , timer(new QTimer(this)) //给时间事件对象实例化空间 { ui->setupUi(this); // id2 = startTimer(2000); //将系统提供的timeout信号和自定义槽连接 connect(timer, &QTimer::timeout, this, &Widget::timeout_slot); } Widget::~Widget() { delete ui; } //定时器超时时,自动执行的功能函数 void Widget::timerEvent(QTimerEvent *e) { //判断哪个定时器超时 if(e->timerId() == id) { // static int num =0; // ui->label->setNum(++num); //获取系统时间 QTime sys_time = QTime::currentTime(); //将时间转换成字符串 QString t = sys_time.toString("hh--mm--ss"); //将系统时间放入lab中 ui->label->setText(t); //文本居中显示 ui->label->setAlignment(Qt::AlignCenter); } } //启动按钮对应的槽函数 void Widget::on_pushButton_clicked() { if(ui->pushButton->text() == "启动") { //启动一个定时器 id = startTimer(1000); //每隔1秒钟,自动执行timerEvent()函数 //将文本设置“关闭” ui->pushButton->setText("关闭"); } else { //关闭定时器 killTimer(id); //将文本设置“启动” ui->pushButton->setText("启动"); } } //启动按钮2对应的槽函数 void Widget::on_pushButton_2_clicked() { if(ui->pushButton_2->text() == "启动") { //启动一个定时器 timer->start(1000);//每隔1秒钟,自动出发timeout信号 //将文本设置“关闭” ui->pushButton_2->setText("关闭"); } else { //关闭定时器 timer->stop(); //将文本设置“启动” ui->pushButton_2->setText("启动"); } } void Widget::timeout_slot() { //获取系统时间 QTime sys_time = QTime::currentTime(); //将时间转换成字符串 QString t = sys_time.toString("hh--mm--ss"); //将系统时间放入lab中 ui->label_2->setText(t); //文本居中显示 ui->label_2->setAlignment(Qt::AlignCenter); }
三、键盘事件 QKeyEvent
3.1 概念
当程序员使用键盘(按下,抬起)时,自动执行对应的功能函数。
3.2 重写的功能函数
[virtual protected] void QWidget::keyPressEvent(QKeyEvent *event); //键盘按下事件函数的声明 [virtual protected] void QWidget::keyReleaseEvent(QKeyEvent *event); //键盘抬起事件函数的声明
3.3 QKeyEvent中常用的函数
int key() const // 键盘上键对应的键值 QString text() const //键盘上键对应的文本,比如大小写
案例:
Ui界面
头文件:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include<QKeyEvent> //键盘事件类 QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); //键盘按下事件函数的声明 void keyPressEvent(QKeyEvent *event) override; //键盘抬起事件函数的声明 void keyReleaseEvent(QKeyEvent *event) override; private: Ui::Widget *ui; }; #endif // WIDGET_H
源文件:
#include "widget.h" #include "ui_widget.h" #include<QDebug> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); } Widget::~Widget() { delete ui; } //重写键盘按下事件函数的实现 void Widget::keyPressEvent(QKeyEvent *event) { //qDebug() << "张峪熙不要睡了。。。"; //ui->label->setText(QString("%1被按下").arg(event->text())); QString s = QString("%1被按下").arg(event->text()); ui->label->setText(s); //判断是否是'W'按下 往上跑 switch (event->key()) { case 'W': { if(ui->label->y()<0-ui->label->height()) { ui->label->move(ui->label->x(), this->height()); } ui->label->move(ui->label->x(),ui->label->y()-5); } } } //重写键盘抬起事件函数的实现 void Widget::keyReleaseEvent(QKeyEvent *event) { QString s = QString("%1被抬起").arg(event->text()); ui->label->setText(s); }
四、鼠标事件 QMouseEvent
4.1 概念
当程序员使用鼠标时,自动执行对应的功能函数。
4.2 重写的功能函数
[virtual protected] void QWidget::mouseDoubleClickEvent(QMouseEvent *event);//鼠标双击事件函数 [virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event);//鼠标移动事件函数 [virtual protected] void QWidget::mousePressEvent(QMouseEvent *event);//鼠标按下事件函数 [virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event);//鼠标抬起事件函数
4.3 QMouseEvent中常用的函数
button() ------>使用鼠标时,该函数判断哪个键被按下 buttons() ------>针对于鼠标移动时,判断哪个键被按下 pos() -------->当前鼠标所在的位置 globalPos() ------->鼠标针对于全局的坐标点 x() ------->x坐标点 y() ------->y坐标点
案例:
头文件:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include<QKeyEvent> //键盘事件类 #include<QMouseEvent> //鼠标事件类 QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); void mousePressEvent(QMouseEvent *event) override;//鼠标按下事件函数声明 void mouseReleaseEvent(QMouseEvent *event) override;//鼠标抬起事件函数声明 void mouseDoubleClickEvent(QMouseEvent *event) override;//鼠标双击事件函数声明 void mouseMoveEvent(QMouseEvent *event) override;//鼠标移动事件函数声明 private: Ui::Widget *ui; }; #endif // WIDGET_H
源文件:
#include "widget.h" #include "ui_widget.h" #include<QDebug> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //开启鼠标追踪功能 this->setMouseTracking(true); } Widget::~Widget() { delete ui; } //重写鼠标按下事件函数实现 void Widget::mousePressEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { ui->label->setText(QString("左键被按下(%1,%2)").arg(event->x()).arg(event->y())); } else if(event->button() == Qt::RightButton) { ui->label->setText(QString("右键被按下(%1,%2)").arg(event->x()).arg(event->y())); } else if(event->button() == Qt::MidButton) { ui->label->setText(QString("中间键被按下(%1,%2)").arg(event->x()).arg(event->y())); } } //重写鼠标抬起事件函数实现 void Widget::mouseReleaseEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { ui->label->setText(QString("左键被抬起(%1,%2)").arg(event->x()).arg(event->y())); } else if(event->button() == Qt::RightButton) { ui->label->setText(QString("右键被抬起(%1,%2)").arg(event->x()).arg(event->y())); } else if(event->button() == Qt::MidButton) { ui->label->setText(QString("中间键被抬起(%1,%2)").arg(event->x()).arg(event->y())); } } //重写鼠标双击事件函数实现 void Widget::mouseDoubleClickEvent(QMouseEvent *event) { if(event->button() == Qt::LeftButton) { ui->label->setText(QString("左键被双击(%1,%2)").arg(event->x()).arg(event->y())); } else if(event->button() == Qt::RightButton) { ui->label->setText(QString("右键被双击(%1,%2)").arg(event->x()).arg(event->y())); } else if(event->button() == Qt::MidButton) { ui->label->setText(QString("中间键被双击(%1,%2)").arg(event->x()).arg(event->y())); } } //重写鼠标移动事件函数实现 void Widget::mouseMoveEvent(QMouseEvent *event) { ui->label->move(event->pos()); }
纯净窗口的移动
头文件:
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include<QMouseEvent> //鼠标事件类 #include<QPoint> //向量类 QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); void mouseMoveEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override; private: Ui::Widget *ui; QPoint p; //记录鼠标在当前窗口的位置 }; #endif // WIDGET_H
源文件:
#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //设置纯净窗口 this->setWindowFlag(Qt::FramelessWindowHint); } Widget::~Widget() { delete ui; } void Widget::mouseMoveEvent(QMouseEvent *event) { //判断是否是左键被按下 if(event->buttons() == Qt::LeftButton) { //窗口移动 this->move(event->globalPos() - p); //全局坐标 当前窗口坐标 } } void Widget::mousePressEvent(QMouseEvent *event) { p = event->pos(); //鼠标在当前窗口的坐标 }