Qt 改变窗口显示透明度 + 光标显示形状的属性(4)
文章目录
- windowOpacity属性
- API接口
- 代码 + 程序演示
- 两个问题
- cursor属性
- API接口
- 代码 + 程序演示
- 直接编辑图形化界面
- 通过纯代码的方式
- Qt允许通过自定义的图片来设置光标
简介:这两个属性我还是觉得非常有用的,对于丰富界面的多样性起到了很大的帮助,而且Qt的自定义光标显示形状使其可玩性提高许多
windowOpacity属性
API接口
API | 说明 |
---|---|
windowOpacity() | 获取到控件的不透明数值,返回float,取值为0.0~1.0,其中0.0表示全透明,1.0表示完全不透明 |
setWindowOpacity() | 设置控件的不透明数值 |
opacity相比于叫做透明度,可能叫做不透明度更合适,因为它数值越大,反而越不透明
代码 + 程序演示
-
动图演示
-
程序设计思路
- 定义两个按钮,一个按钮对象名(
objectName
)为pushButton_add
,另一个按钮名为pushButton_sub
,这是为了后续访问和获取到按钮对象的对象名 - 分别定义两个按钮的槽函数(
直接转到槽定义
),首先先获取到该窗口的透明度【float opacity = this->windowOpacity()
】,判断一下如果该透明度大于等于1.0
或小于等于0.0
,就直接return
- 点击
+
按钮,透明度+0.1
,点击-
按钮,透明度-0.1
。再重新设置该窗口的透明度【this->setWindowOpacity(opacity)
】 控件和窗口都是可以去设置透明度的,咱们这里用窗口举例子
- 定义两个按钮,一个按钮对象名(
-
代码展示
#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::on_pushButton_add_clicked()
{// 先获取到窗口控件的透明度float opacity = this->windowOpacity();// 判断该透明度是否大于等于1if (opacity >= 1.0)return;// 点击按钮一次,透明度+0.1opacity += 0.1;qDebug() << opacity;// 重新设置该窗口的透明度this->setWindowOpacity(opacity);
}void Widget::on_pushButton_sub_clicked()
{float opacity = this->windowOpacity();if (opacity <= 0.0)return;opacity -= 0.1;qDebug() << opacity;this->setWindowOpacity(opacity);
}
两个问题
- 窗口的不透明度,变化并非是精确的
- 在C语言进阶的部分,数据在内存中的存储中有:整数在内存中的存储(原码反码补码,字节序),浮点数在内存中的存储。这里就涉及到浮点数在内存中存储的内容
- IEEE 754标准规定了浮点数要使用二进制科学计数法的方式来表示,把一个浮点数分成了三个部分:
1.符号位,2.有效数字,3.指数部分
。一个浮点数表示为(-1)s x 1.M x 2E,其中s是符号位(0表示正数,1表示负数)
,M是有效数字,表示小数部分
,E是指数部分
- 对于规格化的浮点数,有效数字M只存储小数部分的二进制位,整数部分默认是1,不需要显示存储
- 二进制的第一个有效数字位表示
0.5
,第二个有效数字位表示0.25
,第三个有效数字位表示0.125
,后面依次除2。二进制101
→表示小数0.625
,也可以说小数0.625
用二进制101
来存储 - 像
0.1
这样的小数,由于float
和double
有效数字部分长度都是有限的,导致无法凑出一个非常非常接近0.1
这样的数字 - 很多编程语言(C++/C,Java,Python,Go等)都是采用这套体系,它的优点是:
运算速度快,占用空间小(这是因为CPU制造的时候针对这种运算专门优化的)
。它的缺点是:对于有些小数无法精确表示
- 平时在写代码,千万不能把两个浮点数直接使用
==
进行比较,比如0.1 + 0.2 == 0.3
这种写法就是错误的,正确写法得作差,去判定差的绝对值小于预期误差范围 - 后续工作编写代码的时候,尤其是涉及到一些需要精确计算的场景(比如跟钱打交道的)一定要慎重使用
float/double
// 判断该透明度是否大于等于1if (opacity >= 1.0)return;if (opacity <= 0.0)return;
- 上述代码中,在进行设置之前,先判定了
opacity
的范围,然后再决定是否要设置,这个判断其实可以不写,为啥这里仍要写上?- 这里加了判定条件,实际上不加这样的条件,代码也是OK的,超过1.0这样的数字设置不进去,这是因为
setWindowOpacity
内部也进行了判定 - 其实很多时候写代码的时候,往往是要把一个大的项目拆分成几个部分/模块,由不同的人负责分别完成。往往模块之间要进行交互,比如模块 A 提供API(函数,类)给模块 B 调用
- 别人在使用你所提供的API来进行调用的时候,你是否要对传入的参数进行检查呢?当你要传一个实参,你也不知道这个参数是否是一个 NULL 指针,是否应该在调用函数之前就对这个指针进行判空呢?
- 在《代码大全》这本书中阐述了一种
防御性编程
这种写法,就对上面的情况进行了详细的讨论,防御性编程
可以与防御性驾驶
作类比,也就是咱在驾驶的过程中,遵守交规,做好一切准备,那别人犯错了,不会对咱们自身构成太大的伤害 - 下面的两段代码采用哪段代码去判定呢?代码大全中给出的结论:
要双重判定(double check)
。注意,函数的定义和调用是两伙人,万一对方失误了,没有判定呢?使用double check
,意外着任何一方出错,都不会产生严重的后果
- 这里加了判定条件,实际上不加这样的条件,代码也是OK的,超过1.0这样的数字设置不进去,这是因为
Test* t;
if (t != nullptr)func(t);
void func(Test* t)
{if (t == nullptr)...
}
Test* t;
func(t);
这里推荐一本《代码大全》这本书,这本书它不讲任何一门编程语言,不讨论数据结构算法,只讲如何把代码写好,写规范,这在编程中是通用的,无论是写C++,C语言,java等语言都能从中受益,不过建议以后有一定的工作经验,做了一些项目时可以仔细阅读这本书,因为其中的结论只有真正碰到了问题,真正思考过如何解决问题时才能醍醐灌顶
cursor属性
API接口
API | 说明 |
---|---|
cursor() | 获取到当前 widget 的 cursor 属性,返回 QCursor 对象。当鼠标悬停在该 widget 上时,就会显示出对应的形状。 |
setCursor(const QCursor& cursor) | 设置该 widget 光标的形状。仅在鼠标停留在该 widget 上时生效。 |
QGuiApplication::setOverrideCursor(const QCursor& cursor) | 设置全局光标的形状。对整个程序中的所有 widget 都会生效,覆盖上面的 setCursor 设置的内容。 |
第一个与第二个接口针对的是
Widget
级别的,同一个界面中,不同的控件可以设置成不同的光标。第三个接口设置全局光标(程序内的全局,而不是系统级别的全局)
代码 + 程序演示
直接编辑图形化界面
要搞清楚右上角操作的对象控件,这里也是存在与下面相同的情况,当你只给窗口设置光标的显示形状,按钮上没设置,但也会在按钮上显示更改的光标显示形状。
但是你也给按钮单独设置了一个光标显示形状,那就各自显示各自的,下面情况也是相同的
通过纯代码的方式
-
动图演示
-
程序设计思路
- 思路很简单,让鼠标放到按钮上光标变成等待的圆圈,放到窗口上不显示等待的圆圈
- 先获取到Qt中内置的光标形状【
QCursor cursor(Qt::WaitCursor
】,这里也无需将该对象挂到对象树上 - 重新设置鼠标放在按钮处光标的显示形状【
ui->pushButton->setCursor(cursor)
】 - 这里发现一种特殊情况:
当我去单独设置鼠标放在窗口上时,光标的显示形状为等待圆圈,但鼠标放在按钮上也是等待的圆圈
。这里我猜测是该QPushButton
继承自QWidget
的缘故。上级咋做,下级就跟着怎么做
- 如果你想找到Qt中内置的光标形状可以按下面方式去寻找
-
代码展示
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 先获取到设置窗口光标显示的鼠标形状QCursor cursor(Qt::WaitCursor);// 然后重新设置该光标的形状即可this->setCursor(cursor); // 特殊情况// ui->pushButton->setCursor(cursor);
}Widget::~Widget()
{delete ui;
}
Qt允许通过自定义的图片来设置光标
- 动图演示
- 程序设计思路
- 先准备一张图片,将该图导入到项目中(qrc管理),在代码中访问到这个图片,基于这个图片构造出光标对象并设置,具体如何导入图片,可以参考这篇文章qrc机制
- 先访问到图片文件【
QPixmap pixmap(" : / luoxiaohei.png")
】,这里也无需挂到对象树上,至于为啥这么传参,可以去参考上面提到的文章 - 构造光标对象【
QCursor cursor(pixmap)
】,这个在默认情况下鼠标点击时,相当于图片的左上角在进行点击,如果想让图片中的某一个点作为鼠标点击,可以这么写【QCursor cursor(pixmap, 15, 15)
】,后面两参数就是热点
所在的位置,以图片左上角为(0,0)
原点,找到(10,10)
这个位置作为鼠标真正点击的位置 - 重新设置窗口光标的显示形状【
this->setCursor(cursor)
】 - 也能通过该函数对这个图片进行缩放,注意缩放不是修改图片对象本身,而是返回一个新的图片对象副本【
pixmap = pixmap.scaled(100,100)
】,想要理想的缩放,可以去通过调整参数去观察 - 推荐一个阿里巴巴矢量图标库(免费下载)
- 代码展示
其实还可以给鼠标放到按钮处单独设置一个光标形状,这样鼠标放在窗口和按钮处的光标形状就不同
#include "widget.h"
#include "ui_widget.h"
#include<QLabel>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);// 访问到图片文件QPixmap pixmap(":/luoxiaohei.png");// 调整该图片的缩放pixmap = pixmap.scaled(50,50);//创建光标形状QCursor cursor(pixmap);// QCursor cursor(pixmap, 15, 15); 以热点(15,15)点击// 将窗口显示光标重新设置this->setCursor(cursor);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()
{// 当按钮点击后,将label中的文本进行替换if (ui->label->text() == QString("罗小黑来喽,通通闪开")){ui->label->setText("大家好啊!我是罗小黑");}else{ui->label->setText("罗小黑来喽,通通闪开");}
}