目录
- 第三天
-
- [1 自定义控件封装](#1 自定义控件封装)
- [2 QT鼠标事件](#2 QT鼠标事件)
- [3 定时器](#3 定时器)
- [4 event事件分发器](#4 event事件分发器)
- [5 事件过滤器](#5 事件过滤器)
- [6 绘图事件Qpainter](#6 绘图事件Qpainter)
源码:CPP学习代码
第三天
1 自定义控件封装
新建一个QT widgetclass,同时生成ui,h,cpp文件
在smallWidget.ui里添加上你想要的控件并调试大小
回到mainwidget.ui,拖入一个widget(因为我们封装的也是widget),右击提升为,输入名字(名字一定要写对)。
此时还需要进入mainWidget.h,按住ALT进入"ui_mainWidget.h",修改smallWidget的<>为引号""(""是本地的头文件),这时候运行就能看到我们的控件了。
在smallwidget.cpp里编写代码,让这两个控件QspinxBox和QSilder联系起来,查找手册里的信号和槽,没有就查找父类
cpp
//QspinxBox移动,QSlider跟着移动 查手册,没有就查父类
connect(ui.spinBox,&QSpinBox::valueChanged,ui.horizontalSlider,&QSlider::setValue);
//QSilder移动,QspinxBox跟着移动
connect(ui.horizontalSlider, &QSlider::sliderMoved,ui.spinBox, &QSpinBox::setValue);
再添加两个按钮,一个显示值,一个让值变成一半
在smallwidget头文件里定义两个函数,并到cpp里实现
cpp
//设置值
void setNumber(int value);
//得到值
int getNumber();
void smallWidget::setNumber(int value)
{
//设置值
ui.spinBox->setValue(value);
}
int smallWidget::getNumber()
{
//返回值
return ui.spinBox->value();
}
再到mainwidget.cpp里实现信号的连接,由于smallwi是连接到mainwi里边的widget,所以可以通过ui来访问widget来得到我们定义的函数
cpp
//点击获取值
connect(ui.btn1,&QPushButton::clicked,[=](){
qDebug()<< ui.widget->getNumber();
});
//点击设置值
connect(ui.btn2, &QPushButton::clicked, [=]() {
ui.widget->setNumber(50);
qDebug() << ui.widget->getNumber();
});
2 QT鼠标事件
Enterevent,鼠标进入这个控件就会被捕捉。
不想用ui,只想用自定义事件来捕捉鼠标,就新建一个QTclass,只要h和cpp。查询手册鼠标进入和鼠标退出的函数,直接复制。
cpp
//鼠标进入
void enterEvent(QEnterEvent* event);
//鼠标离开
void leaveEvent(QEvent* event);
void mylabel::enterEvent(QEnterEvent * event)
{
qDebug() <<"鼠标进入了";
}
void mylabel::leaveEvent(QEvent* event)
{
qDebug() << "鼠标离开了";
}
在ui中拖入label,因为我们使用的Qlabel,所以这个mylabel.h和cpp应该继承QLabel,更改以下三处
然后跟上边一样将这个更主界面连接起来,ui界面右键提升为,输入名字,然后修改ui_mainWidget.h里边将mylabely的引用改为""。此时运行就会发现能够捕捉到鼠标
在查询手册,QLabel还有很多对鼠标的操作,我们直接复制来实现,可以在点击时实现输出,移动时输出需要更改因为移动是一个过程。Qstring格式化输出Qstring(%1 %2).arg(参数1).arg(参数2)
cpp
void mylabel::mousePressEvent(QMouseEvent* ev)
{
//QT6很多都删了但是还能使用,不推荐
if(ev->button() == Qt::LeftButton)
{
QString str = QString("鼠标按下 x =%1 y =%2 globalx=%3 ").arg(ev->pos().x()).arg(ev->pos().y()).arg(ev->globalPosition().toPoint().x());
qDebug() << str;
}
}
void mylabel::mouseReleaseEvent(QMouseEvent* ev)
{
if (ev->button() == Qt::LeftButton)
{
qDebug() << "鼠标释放";
}
}
void mylabel::mouseMoveEvent(QMouseEvent* ev)
{
//因为移动是个过程,所以直接==不能够触发,这边用的是buttons,里边包含了三种状态,使用与操作符,当状态和Leftbutton相同时触发
if (ev->button() & Qt::LeftButton)
{
qDebug() << "鼠标移动111";
}
}
在构造函数里添加上鼠标追踪,就不用判断是否点击或者移动来打印信息,会实时打印
cpp
mylabel::mylabel(QWidget*parent)
: QLabel(parent)
{
//设置鼠标追踪,默认false
setMouseTracking(true);
}
3 定时器
使用时间间隔来做出动作,可以让数加一。首先得在头文件里重写定时器事件timerEvent,可以定义定时器的id,startimer启动定时器,让不同的控件有不同的时间间隔,通过timerId()来指定对应的计时器。第二种方式,直接使用QTimer新建一个对象,使用timeout信号连接即可。
cpp
//.h
//重写定时器事件
void timerEvent(QTimerEvent *event);
int id1;//定时器的id
int id2;//定时器的id
//.cpp
#include <QTimer>
mainWidget::mainWidget(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
//启动定时器
id1 = startTimer(1000);//单位毫秒,每隔一秒调用函数
id2 = startTimer(2000);//单位毫秒,每隔2秒调用函数
//定时器的第二种方式
QTimer* timer = new QTimer(this);
//启动定时器
timer->start(500);
connect(timer,&QTimer::timeout,[=](){
static int num2 = 1;
ui.label3->setText(QString::number(num2++));
});
//点击按钮暂停
connect(ui.btn1,&QPushButton::clicked,\[=\](){
timer->stop();
});
}
mainWidget::~mainWidget()
{}
void mainWidget::timerEvent(QTimerEvent * event)
{
if (event->timerId() == id1)
{
static int num = 1;
ui.label2->setText(QString::number(num++));
}
// //两秒跳一次
//if (event->timerId() == id2)
//{
// static int num2 = 1;
// ui.label3->setText(QString::number(num2++));
//}
}
4 event事件分发器
每个发出的响应都会经过这个事件分发器,如果返回true就直接截胡了,相当于你点击鼠标是不触发鼠标点击而触发你定义的事件
type里边有很多的事件
如果返回值是true代表用户需要拦截处理这个事件不向下分发
cpp
//.h
//通过Event事件分发器拦截鼠标按下事件
bool event(QEvent *e);
//.cpp
bool mylabel::event(QEvent* e)
{
//如果是鼠标按下,在event事件分发中做拦截操作
if (e->type() == QEvent::MouseButtonPress)
{
//类型转换,e是ev的父类
QMouseEvent* ev = static_cast<QMouseEvent*>(e);
QString str = QString("鼠标按下222 x =%1 y =%2 globalx=%3 ").arg(ev->pos().x()).arg(ev->pos().y()).arg(ev->globalPosition().toPoint().x());
qDebug() << str;
return true;//代表用户自己处理这个事件
}
//其他事件交给父类处理,默认处理
return QLabel::event(e);
}
5 事件过滤器
相当于拦截了事件分发器。使用过程两个步骤,1、给控件安装事件过滤器,2、重写eventfilter事件
cpp
//.h
//在widget中重写eventfilter事件
bool eventFilter(QObject *watched, QEvent *event);
//.cpp
//给label1安装事件过滤器
//1、构造函数里安装事件过滤器
ui.label1->installEventFilter(this);
//2、重写事件,obj就是控件
bool mainWidget::eventFilter(QObject* watched, QEvent* event)
{
if (watched == ui.label1)
{
if (event->type() == QEvent::MouseButtonPress)
{
//类型转换,e是ev的父类
QMouseEvent* ev = static_cast<QMouseEvent*>(event);
QString str = QString("事件过滤器鼠标按下 x =%1 y =%2 globalx=%3 ").arg(ev->pos().x()).arg(ev->pos().y()).arg(ev->globalPosition().toPoint().x());
qDebug() << str;
}
}
//默认交给父类处理
return QWidget::eventFilter(watched,event);
}
6 绘图事件Qpainter
整体比较简单。只需要重写panitEvent事件,并且声明画家对象,笔刷画笔也只需要先声明对象。
cpp
//.h
//绘图事件
void paintEvent(QPaintEvent *);
//.cpp
void mainWidget::paintEvent(QPaintEvent*)
{
//实例化画家对象,this指定的是绘图设备
QPainter painter(this);
//设置画笔
QPen pen(QColor(255,0,0));
pen.setWidth(3);//宽度
pen.setStyle(Qt::DotLine);//风格
//使用画笔,红色
painter.setPen(pen);
//画刷,会填充封闭的图形
QBrush brush(QColor(0,255,0));
painter.setBrush(brush);
//画线
painter.drawLine(QPoint(0,0),QPoint(100,100));
//画圆
painter.drawEllipse(QPoint(100,100),50,50);
//画矩形
painter.drawRect(50,50,50,50);
//画文字
painter.drawText(QRect(10,200,150,50),"学习");
}