事件
示例程序地址
事件分发机制
当某个事件(鼠标、键盘)发生的时候,窗口就会收到这个事件,并且调用相应的事件处理函数,事件处理函数的命名都是以Event结尾的。
事件先会到达窗口的event函数 , event函数 返回值:true表示该事件得到处理,如果是false,没被处理,事件会继续传递到父窗口通过判断QEvent 参数的类型得知事件的类型后,调用相应的事件处理函数。
//判断event的类型
if(e->type()==QEvent::MouseMove)
{
this->mouseMoveEvent(static_cast<QMouseEvent *>(e));
return true;
}
//其他没有被处理的事件,就使用父类的event
return QLabel::event(e);
鼠标事件
mousePressEvnet,mouseReleseEvent,mouseMoveEvent
mousePressEvnet
通过获取鼠标事件处理函数的参数,获取它的坐标和点击了哪个按键
//获取坐标
int x = ev->x();
int y = ev->y();
//获取鼠标按键
Qt::MouseButton btn = ev->button();
mouseMoveEvent
//获取鼠标按键,这里要使用buttons,获取的鼠标按钮的枚举值按位或的一个值
Qt::MouseButtons btns = ev->buttons();
//通过按位与的方式来提取按了哪个按键
if(btns & Qt::LeftButton)
{
strButton += “LeftButton;”;
}
默认情况下,窗口不会主动跟踪鼠标
只有当某个鼠标按键按下的情况下才开始跟踪
如果想一开始跟踪,就要使用以下函数
this->setMouseTracking(true);
事件过滤器
1 窗口调用installEventFilter来安装一个事件过滤器
2 参数是一个事件过滤器对象QObject,该对象的类要重写eventFilter的函数
事件过滤的时候,事件会先到达事件过滤器的eventFilter函数
对象可以使用自己作为自己的过滤器
返回值:true表示拦截,false表示不拦截,不拦截情况下事件会继续的到达窗口
bool MyLabel::eventFilter(QObject *watched, QEvent *event)
{
if(event->type()==QEvent::MouseMove)
{
//返回true 表示拦截该事件
return true;
}
return false;
}
mylabel1.h
protected:
//重写鼠标案件处理函数
void mousePressEvent(QMouseEvent *ev);
//重写鼠标移动的处理函数
void mouseMoveEvent(QMouseEvent *ev);
//重写鼠标释放的处理函数
void mouseReleaseEvent(QMouseEvent *ev);
//重写事件分发器
bool event(QEvent *e);
//重写对象过滤器eventFilter
bool eventFilter(QObject *watched, QEvent *event);
mylabel1.cpp
#include "mylabel1.h"
#include <QMouseEvent>
#include <QDebug>
mylabel1::mylabel1(QWidget *parent) : QLabel(parent)
{
//默认情况下,窗口不糊主动跟踪鼠标
//只有当鼠标按键按下的情况才开始跟踪
//如果想一开始就跟踪,就要使用以下函数
this->setMouseTracking(true);
//事件过滤器的使用
//1、窗口调用installEventFilter来安装一个事件过滤器
//2 参数是一个事件过滤器对象QObject ,该对象的类要重写eventFilter的函数
//事件过滤的时候,事件会先到达事件过滤器的eventFilter函数
//返回值:true表示拦截,false表示不拦截,不拦截情况下事件会继续到达窗口
this->installEventFilter(this);
}
void mylabel1::mousePressEvent(QMouseEvent *ev)
{
//输出鼠标事件一些信息
//获取坐标
int x = ev->x();
int y = ev->y();
//获取鼠标按钮
Qt::MouseButton btn = ev->button();
QString strButton = "";
if(btn == Qt::LeftButton)
{
strButton = "LeftButton";
}
if(btn == Qt::RightButton)
{
strButton = "RightButton";
}
if(btn == Qt::MidButton)
{
strButton = "MidButton";
}
//label可以显示html
QString str = QString("<h1><center>press[%1,%2][%3]</center></h1>").arg(x).arg(y).arg(strButton);
this->setText(str);
}
void mylabel1::mouseMoveEvent(QMouseEvent *ev)
{
//输出鼠标事件一些信息
//获取坐标
int x = ev->x();
int y = ev->y();
//获取鼠标按钮
Qt::MouseButtons btns = ev->buttons();
QString strButton = "";
if(btns & Qt::LeftButton)
{
strButton += "LeftButton;";
}
if(btns & Qt::RightButton)
{
strButton += "RightButton;";
}
if(btns & Qt::MidButton)
{
strButton += "MidButton";
}
//label可以显示html
QString str = QString("<h1><center>move[%1,%2][%3]</center></h1>").arg(x).arg(y).arg(strButton);
this->setText(str);
}
void mylabel1::mouseReleaseEvent(QMouseEvent *ev)
{
qDebug()<<"鼠标松开了";
}
bool mylabel1::event(QEvent *e)
{
//返回值:true表示该事件得到处理,如果时false,没有被处理,事件会继续传递到父窗口
//QEvent就是所有Event类的父类
//判断event的类型
if(e->type() == QEvent::MouseMove)
{
this->mouseMoveEvent(static_cast<QMouseEvent *>(e));
return true;
}
return QLabel::event(e);
}
bool mylabel1::eventFilter(QObject *watched, QEvent *event)
{
if(event->type() == QEvent::MouseMove)//拦截鼠标移动按键
{
//返回true,表示拦截
return true;
}
return false;
}
定时器事件
闹钟就是定时器,闹钟响了就是定时器事件
timerEvent
通过startTimer来启动一个定时器,参数是毫秒,每隔相应的时间就会触发一个定时器事件
返回值就是定时器的id
通过killTimer来杀死一个定时,参数就是定时器的id
timerEvent定时器事件处理函数中通过event参数获取到当前事件是哪个定时器发出的,event->timerId()
另一种定时器
使用QTimer 的方式创建定时器
通过关注信号 timeout 来接受定时器到时间的信号
通过start 来启动定时器,参数是信号触发间隔的毫秒
通过stop来停止定时器
定时器代码:
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTimer>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
//定时器id
int mTimeId;
//定时器
QTimer *mTimer;
protected:
void timerEvent(QTimerEvent *event);
private slots:
void on_pushButton_start_clicked();
void on_pushButton_stop_clicked();
void on_pushButton_start_3_clicked();
void on_pushButton_stop_3_clicked();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QTimer>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//创建定时器
//startTimer(1000);
}
Widget::~Widget()
{
delete ui;
}
void Widget::timerEvent(QTimerEvent *event)
{
static int num = 1;
this->ui->lcdNumber->display(num++);
}
void Widget::on_pushButton_start_clicked()
{
//创建定时器 设置1秒一次
this->mTimeId = startTimer(1000);
}
void Widget::on_pushButton_stop_clicked()
{
//停止定时器
killTimer(mTimeId);
}
void Widget::on_pushButton_start_3_clicked()
{
mTimer = new QTimer(this);
connect(mTimer,&QTimer::timeout,[=](){
static int num = 1;
this->ui->lcdNumber_3->display(num++);
});
mTimer->start(10);
}
void Widget::on_pushButton_stop_3_clicked()
{
mTimer->stop();
}
重新画按钮
1 什么时候画
绘图事件:窗口需要重新显示的时候,就会收到一个绘图事件 paintEvent
收到绘图事件之后,窗口就要将自己画出来
2 怎么画
画画的人 —— QPainter
画笔 —— QPen
画布 —— QPaintDevice
QPainter ( 参数是绘图设备 ,this表示在窗口上绘图)
drawLine 划线 , 两点成一线,参数就是两个点的坐标
drawRect 矩形 , 参数是 左上角的点和 宽和高
drawEllips 画椭圆 , 参数是 左上角的点和 宽和高 ,另一种方式就是 圆心 + rx + ry
设置画家的画笔
setPen ( QPen) ,画笔可以设置颜色和风格
设置画家的画刷
setBrush(QBrush) , 填充封闭的图形, 也可以设置颜色 ,默认情况下,画刷不填充,还得设置风格
搬动画家
translate ( x, y) 将画家移动到某个坐标开始画画
手动触发绘图事件
使用两个函数
repaint : 会马上触发绘图事件
update : update做了一些优化 ,比如多次调用只会触发一次事件,建议使用update
注意:不要在paintEvent处理函数中再触发绘图事件,会导致无限循环
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QFile>
#include <QFileDialog>
#include <QTextCodec>
#include <QFileInfo>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
//写文件
QFile file("F:\\test20.txt");
file.open(QIODevice::WriteOnly);
file.write("hello");
file.close();
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
QString fileName = QFileDialog::getOpenFileName(this,"打开一个文件","","ALL(*.*)");
//对fileName做判断,如果没有选择文件,那么就是一个空串
if(fileName.isEmpty())
{
return;
}
else {
//选择了文件,将文件名显示到lineEdit
this->ui->lineEdit->setText(fileName);
}
//使用qfile来读取文件
QFile file(fileName);
//打开文件 以只读方式打开
file.open(QIODevice::ReadOnly);
//读取文件内容
//将所有内容全部读取出来
//QByteArray arry = file.readAll();
//单行读取
QByteArray arry;
do{
arry += file.readLine();
}while(!file.atEnd());
//使用gbk编码
QTextCodec *codec = QTextCodec::codecForName("gbk");
//将arry转换成QString
QString content = codec->toUnicode(arry);
//输出到edit上
this->ui->plainTextEdit->setPlainText(content);
//获取文件信息
QFileInfo info(fileName);
qDebug()<<"文件全名:"<<info.fileName();
qDebug()<<"baseName:"<<info.baseName();
qDebug()<<"路径:"<<info.path();
qDebug()<<"文件是否为目录:"<<info.isDir();
//关闭文件
file.close();
}