前言:
事件(event)是由系统或者 Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件在对用户操作做出响应时发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件。
一、鼠标事件:
1.鼠标进入事件 enterEvent
2.鼠标离开事件 leaveEvent
3.鼠标按下 mousePressEvent ( QMouseEvent ev)
4.鼠标释放 mouseReleaseEvent
5.鼠标移动 mouseMoveEvent
6.ev->x() x坐标 ev->y() y坐标
7.ev->button() 可以判断所有按键 Qt::LeftButton Qt::RightButton
8.ev->buttons()判断组合按键 判断move时候的左右键 结合 & 操作符
9.格式化字符串 QString( “ %1 %2 ” ).arg( 111 ).arg(222)
10.设置鼠标追踪 setMouseTracking(true);
1.mylabel.h
#ifndef MYLABEL_H #define MYLABEL_H #include <QLabel> class myLabel : public QLabel { public: explicit myLabel(QWidget *parent = nullptr); //鼠标进入事件 void enterEvent(QEvent *event); //鼠标离开事件 void leaveEvent(QEvent *); //鼠标按下 virtual void mousePressEvent(QMouseEvent *ev); //鼠标释放 virtual void mouseReleaseEvent (QMouseEvent *ev); //鼠标移动 virtual void mouseNoveEvent (QMouseEvent *ev); signals: }; #endif // MYLABEL_H
2.mylabel.cpp
#include "mylabel.h" #include <QDebug> #include <QMouseEvent> myLabel::myLabel(QWidget *parent) : QLabel(parent) { //设置鼠标追踪状态 setMouseTracking(true); } //鼠标进入事件 void myLabel::enterEvent(QEvent *event) { qDebug() << "鼠标进入了"; } //鼠标离开事件 void myLabel::leaveEvent(QEvent *) { qDebug() << "鼠标离开了"; } //鼠标按下 void myLabel::mousePressEvent(QMouseEvent *ev) { //当鼠标左键按下 提示信息 if(ev->button() == Qt::LeftButton) { QString str = QString("鼠标按下了 x=%1 y=%2 globalX = %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); qDebug() << str; } } //鼠标释放 void myLabel::mouseReleaseEvent (QMouseEvent *ev) { if(ev->button() == Qt::LeftButton) { QString str = QString("鼠标释放了 x=%1 y=%2 globalX = %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); qDebug() << str; } } //鼠标移动 void myLabel::mouseNoveEvent (QMouseEvent *ev) { if(ev->button() & Qt::LeftButton) { QString str = QString("鼠标移动了 x=%1 y=%2 globalX = %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); qDebug() << str; } }
3.mylabel.ui
4.运行效果
二、定时器
1.第一种定时器:
利用事件 void timerEvent ( QTimerEvent * ev)
启动定时器 startTimer( 1000) 毫秒单位
timerEvent 的返回值是定时器的唯一标识 可以和ev->timerId 做比较
(1)widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); //重写定时器的事件 void timerEvent(QTimerEvent *); int id1;//定时器1的唯一标识 int id2;//定时器2的唯一标识 private: Ui::Widget *ui; }; #endif // WIDGET_H
(2)widget.cpp
#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //启动定时器 id1 = startTimer(1000);//参数1 间隔 单位 毫秒 id2 = startTimer(2000); } //重写定时器的事件 void Widget::timerEvent(QTimerEvent *ev) { //label1每隔1秒+1 if(ev->timerId() == id1) { static int num = 1; ui->label_2->setText( QString::number(num++)); } //label2每隔2秒+1 if(ev->timerId() == id2) { static int num2 = 1; ui->label_3->setText( QString::number(num2++)); } } Widget::~Widget() { delete ui; }
(3)widget.ui
(4)运行效果
2.第二种定时器:
利用定时器类 QTimer
创建定时器对象 QTimer * timer = new QTimer(this)
启动定时器 timer->start(毫秒)
每隔一定毫秒,发送信号 timeout ,进行监听
暂停 timer->stop
#include "widget.h" #include "ui_widget.h" #include <QTimer>//定时器的类 Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //定时器的第二种方式 QTimer *timer = new QTimer(this); //启动定时器 timer->start(500); connect(timer,&QTimer::timeout,[=](){ //label4每隔2秒+1 static int num = 1; ui->label_4->setText(QString::number(num++)); }); //点击暂停按钮 实现停止定时器 connect(ui->btn,&QPushButton::clicked,[=](){ timer->stop(); }); } Widget::~Widget() { delete ui; }
三、event事件分发器与过滤器
1.事件分发器
事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是将这些事件对象按照它们不同的类型,分发给不同的事件处理器(event handler)。
如上所述,event()函数主要用于事件的分发。所以,如果你希望在事件分发之前做一些操作,就可以重写这个event()函数了。
用途:用于事件的分发
也可以做拦截操作,不建议
bool event( QEvent * e);
返回值 如果是true 代表用户处理这个事件,不向下分发了
e->type() == 鼠标按下
(1)mylabel.h
#ifndef MYLABEL_H #define MYLABEL_H #include <QLabel> class myLabel : public QLabel { public: explicit myLabel(QWidget *parent = nullptr); //鼠标进入事件 void enterEvent(QEvent *event); //鼠标离开事件 void leaveEvent(QEvent *); //鼠标按下 virtual void mousePressEvent(QMouseEvent *ev); //鼠标释放 virtual void mouseReleaseEvent (QMouseEvent *ev); //鼠标移动 virtual void mouseNoveEvent (QMouseEvent *ev); //通过event事件分发器 拦截 鼠标按下事件 bool event(QEvent *e); signals: }; #endif // MYLABEL_H
(2)mylabel.cpp
#include "mylabel.h" #include <QDebug> #include <QMouseEvent> myLabel::myLabel(QWidget *parent) : QLabel(parent) { //设置鼠标追踪状态 setMouseTracking(true); } //鼠标进入事件 void myLabel::enterEvent(QEvent *event) { qDebug() << "鼠标进入了"; } //鼠标离开事件 void myLabel::leaveEvent(QEvent *) { qDebug() << "鼠标离开了"; } //鼠标按下 void myLabel::mousePressEvent(QMouseEvent *ev) { //当鼠标左键按下 提示信息 if(ev->button() == Qt::LeftButton) { QString str = QString("鼠标按下了 x=%1 y=%2 globalX = %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); qDebug() << str; } } //鼠标释放 void myLabel::mouseReleaseEvent (QMouseEvent *ev) { if(ev->button() == Qt::LeftButton) { QString str = QString("鼠标释放了 x=%1 y=%2 globalX = %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); qDebug() << str; } } //鼠标移动 void myLabel::mouseNoveEvent (QMouseEvent *ev) { if(ev->button() & Qt::LeftButton) { QString str = QString("鼠标移动了 x=%1 y=%2 globalX = %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); qDebug() << str; } } bool myLabel::event(QEvent *e) { //如果是鼠标按下 在event事件分发中做拦截操作 if(e->type() == QEvent::MouseButtonPress) { QMouseEvent * ev = static_cast<QMouseEvent *>(e); QString str = QString("Event函数中:鼠标按下了 x=%1 y=%2 globalX = %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); qDebug() << str; return true;//true代表用户自己处理这个事件,不向下分发 } //其他事件 交给父类处理 默认处理 return QLabel::event(e); }
(3)运行效果
2.事件过滤器
我们已经知道,Qt 创建了QEvent事件对象之后,会调用QObject的event()函数处理事件的分发。显然,我们可以在event()函数中实现拦截的操作。由于event()函数是 protected 的,因此,需要继承已有类。如果组件很多,就需要重写很多个event()函数。这当然相当麻烦,更不用说重写event()函数还得小心一堆问题。好在 Qt 提供了另外一种机制来达到这一目的:事件过滤器。
在程序将时间分发到事件分发器前,可以利用过滤器做拦截
步骤
1、给控件安装事件过滤器
2、重写 eventFilter函数 (obj , ev)
(1)widget.h
#ifndef MYLABEL_H #define MYLABEL_H #include <QLabel> class myLabel : public QLabel { public: explicit myLabel(QWidget *parent = nullptr); //鼠标进入事件 void enterEvent(QEvent *event); //鼠标离开事件 void leaveEvent(QEvent *); //鼠标按下 virtual void mousePressEvent(QMouseEvent *ev); //鼠标释放 virtual void mouseReleaseEvent (QMouseEvent *ev); //鼠标移动 virtual void mouseNoveEvent (QMouseEvent *ev); //通过event事件分发器 拦截 鼠标按下事件 bool event(QEvent *e); signals: }; #endif // MYLABEL_H
(2)widget.cpp
#include "widget.h" #include "ui_widget.h" #include <QTimer>//定时器的类 #include <QMouseEvent> #include <QDebug> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //给label 安装事件过滤器 //步骤1 安装事件过滤器 ui->label->installEventFilter(this); } //步骤2 重写 enentfilter事件 bool Widget::eventFilter (QObject * obj,QEvent * e) { if(obj == ui->label) { if(e->type() == QEvent::MouseButtonPress) { QMouseEvent * ev = static_cast<QMouseEvent *>(e); QString str = QString("事件过滤器中:鼠标按下了 x=%1 y=%2 globalX = %3 globalY = %4").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); qDebug() << str; return true;//true代表用户自己处理这个事件,不向下分发 } } //其他默认处理 return QWidget::eventFilter(obj,e); } Widget::~Widget() { delete ui; }
(3)运行效果
四、绘图事件
Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制。整个绘图系统基于QPainter,QPainterDevice和QPaintEngine三个类。
QPainter用来执行绘制的操作;QPaintDevice是一个二维空间的抽象,这个二维空间允许QPainter在其上面进行绘制,也就是QPainter工作的空间;QPaintEngine提供了画笔(QPainter)在不同的设备上进行绘制的统一的接口。QPaintEngine类应用于QPainter和QPaintDevice之间,通常对开发人员是透明的。
下图给出了这三个类之间的层次结构:
Qt 的绘图系统实际上是,使用QPainter在QPainterDevice上进行绘制,它们之间使用QPaintEngine进行通讯(也就是翻译QPainter的指令)。
1.QPainter 绘图
(1) 绘图事件 void paintEvent()
(2) 声明一个画家对象 QPainter painter(this) this指定绘图设备
(3) 画线、画圆、画矩形、画文字
(4) 设置画笔 QPen 设置画笔宽度 、风格
(5) 设置画刷 QBrush 设置画刷风格
(1)widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); //绘图事件 void paintEvent(QPaintEvent *); private: Ui::Widget *ui; }; #endif // WIDGET_H
(2)widget.cpp
#include "widget.h" #include "ui_widget.h" #include <QPainter> //画家类 #include <QDebug> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); } //绘图事件 void Widget::paintEvent(QPaintEvent *) { //实例化画家对象 this指定的是绘画设备 QPainter painter(this); //设置画笔 QPen pen(QColor(255,0,0)); //设置画笔宽度 pen.setWidth(5); //设置画笔风格 pen.setStyle(Qt::DotLine); //设置画家,使用这个笔 painter.setPen(pen); //设置画刷 QBrush brush(Qt::blue); //设置画刷风格 brush.setStyle(Qt::Dense7Pattern); //让画家使用画刷 painter.setBrush(brush); //画线 painter.drawLine(QPoint(0,0),QPoint(100,100)); //画圆 painter.drawEllipse(QPoint(100,100),50,50); //画矩形 painter.drawRect(QRect(20,20,50,50)); //画文字 painter.drawText(QRect(10,200,150,50),"你好呀QT"); } Widget::~Widget() { delete ui; }
(3)运行效果
2.QPainter高级设置
(1).抗锯齿效率低
painter.setRenderHint(QPainter::Antialiasing);
(2).对画家进行移动
painter.translate(100,0);
保存状态 save
还原状态 restore
(3).如果想手动调用绘图事件 利用update
(4).利用画家画图片 painter.drawPixmap( x,y,QPixmap( 路飞) )
(1)widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); //绘图事件 void paintEvent(QPaintEvent *); int posX = 0; private: Ui::Widget *ui; }; #endif // WIDGET_H
(2)widget.cpp
#include "widget.h" #include "ui_widget.h" #include <QPainter> //画家类 #include <QDebug> #include <QPushButton> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //点击移动按钮 移动图片 connect(ui->toolButton,&QPushButton::clicked,[=](){ posX+=20; //如果想手动调用绘图事件 利用update update(); }); } //绘图事件 void Widget::paintEvent(QPaintEvent *) { //高级设置 QPainter painter(this); //画圆 painter.drawEllipse(QPoint(300,50),50,50); //设置抗锯齿能力 效率较低 painter.setRenderHint(QPainter::Antialiasing); painter.drawEllipse(QPoint(400,50),50,50); //画矩形 painter.drawRect(QRect(20,20,50,50)); //移动画家 painter.translate(100,100); //保存画家状态 painter.save(); painter.drawRect(QRect(20,20,50,50)); painter.translate(100,100); //还原画家保存状态 painter.restore(); painter.drawRect(QRect(20,20,50,50)); //利用画家画资源图片 //如果超出屏幕,再从0开始 if(posX > this->width()) { posX = 0; } painter.drawPixmap(posX,0,QPixmap(":/Image/Luffy.png")); } Widget::~Widget() { delete ui; }
(3)运行效果
3. QPaintDevice绘图设备
QPixmap QImage QBitmap(黑白色) QPicture QWidget
(1) QPixmap 对不同平台做了显示的优化
QPixmap pix( 300,300)
pix.fill( 填充颜色 )
利用画家 往pix上画画 QPainter painter( & pix)
保存 pix.save( “路径”)
(2) Qimage 可以对像素进行访问
使用和QPixmap差不多 QImage img(300,300,QImage::Format_RGB32);
其他流程和QPixmap一样
可以对像素进行修改 img.setPixel(i,j,value);
(3) QPicture 记录和重现 绘图指令
QPicture pic
painter.begin(&pic);
保存 pic.save( 任意后缀名 )
重现 利用画家可以重现painter.drawPicture(0,0,pic);
(1)widget.h
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACE class Widget : public QWidget { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); //绘图事件 void paintEvent(QPaintEvent *); private: Ui::Widget *ui; }; #endif // WIDGET_H
(2)widget.cpp
Pixmap绘图设备 专门未平台做了显示优化
#include "widget.h" #include "ui_widget.h" #include <QPainter> #include <QDebug> #include <QPixmap> //画家类 #include <QImage> #include <QPicture> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //Pixmap绘图设备 专门未平台做了显示优化 QPixmap pix(300,300); //填充颜色 pix.fill(Qt::white); //声明画家 QPainter painter(&pix); painter.setPen(QPen(Qt::green)); painter.drawEllipse(QPoint(150,150),100,100); //保存 pix.save("E:\\桌面文件\\pix.png"); } //绘图事件 void Widget::paintEvent(QPaintEvent *) { } Widget::~Widget() { delete ui; }
QImage 绘图设备 可以对像素进行访问
利用QImage 对象素进行修改
#include "widget.h" #include "ui_widget.h" #include <QPainter> #include <QDebug> #include <QPixmap> //画家类 #include <QImage> #include <QPicture> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //QImage 绘图设备 可以对像素进行访问 QImage img(300,300,QImage::Format_RGB32); img.fill(Qt::white); QPainter painter(&img); painter.setPen(QPen(Qt::blue)); painter.drawEllipse(QPoint(150,150),100,100); //保存 img.save("E:\\桌面文件\\pix.png"); } //绘图事件 void Widget::paintEvent(QPaintEvent *) { QPainter painter(this); //利用QImage 对象素进行修改 QImage img; img.load(":/Image/Luffy.png"); //修改像素点 for(int i = 50;i < 100;i++) { for(int j = 50;j < 100;j++) { QRgb value = qRgb(255,0,0); img.setPixel(i,j,value); } } painter.drawImage(0,0,img); } Widget::~Widget() { delete ui; }
QPicture绘图设备 可以记录和重新绘图指令
#include "widget.h" #include "ui_widget.h" #include <QPainter> #include <QDebug> #include <QPixmap> //画家类 #include <QImage> #include <QPicture> Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) { ui->setupUi(this); //QPicture绘图设备 可以记录和重新绘图指令 QPicture pic; QPainter painter; painter.begin(&pic);//开始往pic上画 painter.setPen(QPen(Qt::red)); painter.drawEllipse(QPoint(150,150),100,100); painter.end();//结束画画 //保存到磁盘 pic.save("E:\\桌面文件\\pic.zt"); } //绘图事件 void Widget::paintEvent(QPaintEvent *) { QPainter painter(this); //重现QPicture绘图指令 QPicture pic; pic.load("E:\\桌面文件\\pic.zt"); painter.drawPicture(0,0,pic); } Widget::~Widget() { delete ui; }