一、事件机制
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_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic: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;//定义一个定时器的idint 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_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic: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_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic: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_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic: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(); //鼠标在当前窗口的坐标 }