Qt学习笔记9——P30-33. 自定义控件封装,鼠标事件,定时器
- P30. 自定义控件封装
- P31. Qt中的鼠标事件
- P32. 定时器1
- P33. 定时器2
- P30. 自定义控件封装(创建了新项目)
- 添加新的界面和类:右键项目的文件夹(顶层的文件)-> Qt——Qt设计师界面类 -> “选择界面模板”选"Widget" -> 在"Class name"中取个类名(此案例中改成了SmallWidget) -> 别的没什么注意的了,点下一步或完成,其他默认
(下面要做的是把“Spin Box”和“Horizontal Slider”封装到一起)
先拖一个Spin Box和Horizontal Slider到新添加的ui界面中,调整整个ui的大小和两个控件的位置(水平对齐)
切换到主的ui编辑界面中,拖一个“Widget”到界面中,右键此Widget -> 提升为 ->新窗口中的“提升的类名称”中填 一开始添加的在“Class name”中的类名 -> 点“全局包含”(说是可点可不点;作用是方便其他相同的提升),点击“添加” -> 再点击“提升”
(此时新添加的Widget的类名不再是QWidget,而变成了SmallWidget)
(下面实现按钮和滑块的同步)
(切换到smallwidget.cpp)
1 //QSpinBox移动 QSlider跟着移动
2 //因为valueChanged重载了,需要用函数指针
3 void(QSpinBox:: * spSignal)(int) = &QSpinBox::valueChanged;
4 connect(ui->spinBox,spSignal,ui->horizontalSlider,&QSlider::setValue);
5
6 //QSlider滑动 QSpinBox数字跟着改变
7 connect(ui->horizontalSlider,&QSlider::valueChanged,ui->spinBox,&QSpinBox::setValue);
运行结果:
(下面实现两个功能:设置数字 和 获取数字)
(切换到smallwidget.h,先声明两个函数)
//设置数字
void setNum(int num);
//获取数字
int getNum();
(在smallwidget.cpp中实现上面的函数)
1 //设置数字
2 void SmallWidget::setNum(int num)
3 {
4 ui->spinBox->setValue(num);
5 }
6 //获取数字
7 int SmallWidget::getNum()
8 {
9 return ui->spinBox->value();
10 }
(widget.cpp)
1 //点击获取 获取控件当前值
2 connect(ui->btn_get,&QPushButton::clicked,this,[=](){
3 qDebug()<<ui->widget1->getNum(); //widget1是封装的控件的widget变量名;getNum()是刚才在smallwidget.cpp中自己写的函数
4 });
5
6 //点击设置到一半
7 connect(ui->btn_set,&QPushButton::clicked,this,[=](){
8 ui->widget1->setNum(50);
9 });
- P31. Qt中的鼠标事件(创建了新项目)
(将要实现的功能:判断鼠标进入和离开一个区域)
往项目中添加新的类,不需要ui界面:右键项目名称 -> Add New -> 左边选C/C++,中间选“C++ Class”,“Choose” -> “Class name”中取个名字(此案例中为“myLabel”),“Base class”选“QWidget” -> 下一步,完成
(mylabel.h)
1 //鼠标进入事件
2 void enterEvent(QEvent * event);
3 //鼠标离开事件
4 void leaveEvent(QEvent *);
(mylabel.cpp)
1 //鼠标进入事件
2 void myLabel::enterEvent(QEvent * event)
3 {
4 qDebug()<<"鼠标进入了";
5 }
6 //鼠标离开事件
7 void myLabel::leaveEvent(QEvent *)
8 {
9 qDebug()<<"鼠标离开了";
10 }
(一个因为之前新建错误 而导致现在必要的操作)
在“mylabel.h”中:
#include <QLabel>
把 class myLabel : public QWidget 改成 class myLabel : public QLabel
在“mylabel.cpp”中:
把 myLabel::myLabel(QWidget *parent) : QWidget(parent) 改成 myLabel::myLabel(QWidget *parent) : QLabel(parent)
往ui编辑界面中拖拽一个"Label",右键 -> 提升为 -> “提升的类的名称”里填“myLabel” -> 添加,提升
(因为这个新添加的控件的基类是QLabel,所以提升的类也要是QLabel,所以刚才要把QWidget改成QLabel)
- ui中的Label添加进去之后,不好找,怎么办?:
选中添加进去的Label,右下角“frameShape”可以选“Box”,就有边框了
运行一下:
(实现几个其他的鼠标功能)
(mylabel.h)
1 //鼠标按下
2 virtual void mousePressEvent(QMouseEvent *ev);
3 //鼠标释放
4 virtual void mouseReleaseEvent(QMouseEvent *ev);
5 //鼠标移动
6 virtual void mouseMoveEvent(QMouseEvent *ev);
(mylabel.cpp)
1 //鼠标按下
2 void myLabel::mousePressEvent(QMouseEvent *ev)
3 {
4 //当鼠标左键按下 提示信息
5 if(ev->button() == Qt::LeftButton)
6 {
7 //如果没有上面的if,这里的操作鼠标左右键都可以进行
8 QString str = QString("鼠标按下了 x = %1 y = %2 globalX = %3 globalY = %4" ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); //%1 和 %2 都是占位的,%1的位置将是ev->x(),%2的位置将是ev->y()
9 qDebug()<<str;
10 }
11
12 }
13 //鼠标释放
14 void myLabel::mouseReleaseEvent(QMouseEvent *ev)
15 {
16 if(ev->button() == Qt::LeftButton)
17 {
18 QString str = QString("鼠标释放了 x = %1 y = %2 globalX = %3 globalY = %4" ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); //%1 和 %2 都是占位的,%1的位置将是ev->x(),%2的位置将是ev->y()
19 qDebug()<<str;
20 }
21
22 }
23 //鼠标移动
24 void myLabel::mouseMoveEvent(QMouseEvent *ev)
25 {
26 if(ev->buttons() & Qt::LeftButton) //跟上面的判断不同:1. buttons 2. &
27 {
28 QString str = QString("鼠标移动了 x = %1 y = %2 globalX = %3 globalY = %4" ).arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY()); //%1 和 %2 都是占位的,%1的位置将是ev->x(),%2的位置将是ev->y()
29 qDebug()<<str;
30 }
31
32 }
1 //设置鼠标追踪
2 setMouseTracking(true);
设置了鼠标追踪后,即使鼠标在区域中不按下,也会显示移动(但是要把判断移动的“if”注释掉)
总结:
- 鼠标进入事件 enterEvent
- 鼠标离开事件 leaveEvent
- 鼠标按下 mousePressEvent(QMouseEvent * ev)
- 鼠标释放 mouseReleaseEvent
- 鼠标移动 mouseMoveEvent
- ev->x() x坐标 ev->y() y坐标
- ev->button() 可以判断左右按键 Qt::LeftButton Qt::RightButton
- ev->buttons() 判断组合按键 判断move时候的左右键 结合 & 操作符
- 格式化字符串 QString("%1 %2").arg(111).arg(222)
- P32. 定时器(沿用了上P项目)
(下面做:每隔一秒数字增加1)
在ui编辑界面里拖拽一个“Label”
(widget.h)
1 //重写定时器事件
2 void timerEvent(QTimerEvent *);
(widget.cpp)
1 //构造函数中
2 //启动定时器
3 startTimer(1000); //参数1.间隔(单位 毫秒)
4 ...
5 void Widget::timerEvent(QTimerEvent *)
6 {
7 static int num = 1; //静态变量
8 ui->label_2->setText(QString::number(num++));
9 }
(下面实现:一个隔一秒+1,一个隔两秒+1)
再往ui编辑界面拖拽一个“Label”
(widget.h)
//public中
int id1; //定时器1的唯一标识
int id2; //定时器2的唯一标识
(widget.cpp)
1 //构造函数中
2 //启动定时器
3 id1 = startTimer(1000); //参数1.间隔(单位 毫秒);startTimer返回的是定时器id
4 id2 = startTimer(2000);
5 ...
6 //全局函数
7 void Widget::timerEvent(QTimerEvent *ev)
8 {
9 if(ev->timerId() == id1)
10 {
11 static int num = 1; //静态变量
12 ui->label_2->setText(QString::number(num++));
13 }
14 if(ev->timerId()==id2)
15 {
16 static int num2=1;
17 ui->label_3->setText(QString::number(num2++));
18 }
19 }
总结:
- 利用事件 void timerEvent(QTimerEvent * ev)
- 启动定时器 startTimer(1000) 单位毫秒
- timerEvent 的返回值是定时器的唯一标识 可以和ev->timerId 作比较
- P33. 定时器2(推荐这种方法)(沿用了上P项目)
定时器第二种方式
(实现每隔0.5s数字+1)
在ui编辑界面再拖拽一个“Label”
(widget.cpp)
1 //构造函数中
2 //定时器第二种方式
3 QTimer * timer = new QTimer(this);
4 //启动定时器
5 timer->start(500); //单位毫秒
6 connect(timer,&QTimer::timeout,this,[=](){
7 static int num3 =1;
8 ui->label_4->setText(QString::number(num3++));
9 });
(下面实现:点一个按钮暂停)
在ui编辑界面拖拽一个“Push Button”(改名“暂停”,变量名“btn”)
(widget.cpp)
1 //点击暂停按钮 实现停止计时器
2 connect(ui->btn,&QPushButton::clicked,this,[=](){
3 timer->stop();
4 });
5 //如果恢复那就再添加一个按钮,然后连接timer->start(间隔)
总结:
- 利用定时器类 QTimer
- 创建定时器对象 QTimer * timer = new QTimer (this)
- 启动定时器 timer->start(毫秒)
- 每隔一定毫秒,发送信号 timeout,进行监听
- 暂停 timer->stop()
(〃>_<;〃)(〃>_<;〃)(〃>_<;〃)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端