一、说明
做 qt 开发也有好几年了,一直基于QWidget 框架做的开发,使用重写 paint 函数实现各种显示效果,在复杂的 ui 开发中,控件一多或者刷新频率一高,其实也是存在性能限制。
一般来说,qt 的界面对象全部在主线程中运行,main 函数中的 exec()阻塞不断进行事件循环驱动。QWidget的绘制和渲染都是基于 cpu 的,所以这个性能上限吧就感觉相对低点。现在 ui 也是越来越复杂,cpu 压力也就越大。虽然可以通过优化代码提升性能,但是这个浮躁的社会,写起代码来,不得更加浮躁!
然而,qml 居然是使用 gpu 做的渲染,这个是不是就很香了。QWidget 已经n 年没有更新,新的 qt 版本都是围绕 qml 和 3D 做的迭代,感觉 qml 才是qt 的未来。
其实也是断断续续学习过qml,怕年纪越来越大,越不愿意接受新鲜事物,现在还有动力,所以要多做一些学习,并写一些相关的文章记录过程。
之前使用 QWidget 也做过电池控件,有兴趣的朋友可以查看链接:https://blog.csdn.net/weixin_42887343/article/details/113932145
二、效果
三、需求
- 最基本的需求就是显示电量了
- 电量小于 20% 显示橙色,小于 10% 显示红色,否则显示绿色
- 可以随意设置电池电量
- 电量变化后,需要有一个渐变的动画
- 需要显示电池电量百分比文字
四、准备
(1)安装 qtCreator,这个大家应该都没有问题。
(2)使用qtCreator创建 qml 项目,可以参考链接:https://blog.csdn.net/weixin_42887343/article/details/135410332
(3)如果对 qml 不熟悉,可以看一下qml 元素详解:https://blog.csdn.net/weixin_42887343/article/details/135356964
五、代码设计
电池控件的 ui 很简单,可以分成几个部分,电池控件组成结构如下图:
qml 作为描述性语言,只要使用 qml 对各个部分做一些描述性定义,然后按上图做包含组合即可实现控件。
(1)电池头
//电池头
Rectangle {
id: batteryHeader
width: batteryContainer.width / 18
height: batteryContainer.height / 2.5
anchors.left:batteryContainer.right
anchors.verticalCenter: batteryContainer.verticalCenter
color: borderColor
radius: 5
Rectangle {
x: 0
y: 0
width: parent.radius
height: parent.height
radius: 0
color: parent.color
}
}
(2)电池电量颜色块
// 电量rect
Rectangle {
id:colorRectiud
width: (batteryContainer.width - 2 * borderWidth)*(batteryLevel)
height: batteryContainer.height - 2 * borderWidth
anchors.verticalCenter: parent.verticalCenter
x: borderWidth
color: colorBasedOnValue(batteryLevel)
radius:5
// 电量颜色获取函数
function colorBasedOnValue(value) {
if (value < 0.1) {
return root.lowerLevelColor;
} else if (value < 0.2) {
return root.lowLevelColor;
} else {
return root.nomalLevelColor; // 默认值或其他颜色
}
}
}
(3)电池电量文字
// 电量文字
Text {
anchors.centerIn: parent
text: Math.floor(batteryLevel * 100) + "%"
font.pixelSize: 20
color: "white"
}
(4)电池体
// 电池体
Rectangle {
id: batteryContainer
width: parent.width - 2 * borderWidth
height: parent.height - 2 * borderWidth
anchors.centerIn: parent
color: borderColor
border.color: borderColor // 设置边界线颜色
border.width: borderWidth // 设置边界线宽度
radius:10
// 电量rect
Rectangle {
……(2)
}
// 电量文字
Text {
……(3)
}
}
(5)电池控件
Rectangle {
id:root
property real batteryLevel: 1
property real borderWidth: 6
property color borderColor: "#aaaaaa"
property color nomalLevelColor: "#4CAF50"
property color lowLevelColor: "#FFC107"
property color lowerLevelColor: "red"
width: 200
height: 100
// 电池体
Rectangle {
……(4)
}
//电池头
Rectangle {
……(1)
}
}
说明
代码中,……(1)表示(1)电池头中对应的代码,……(4)表示第四部分电池体的代码,其他同意思。
从上面代码即可看出,他们的组合关系在代码上即为包含关系。
控件的总代码:
// Battery.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.0
Rectangle {
id:root
property real batteryLevel: 1
property real borderWidth: 6
property color borderColor: "#aaaaaa"
property color nomalLevelColor: "#4CAF50"
property color lowLevelColor: "#FFC107"
property color lowerLevelColor: "red"
width: 200
height: 100
// 电池体
Rectangle {
id: batteryContainer
width: parent.width - 2 * borderWidth
height: parent.height - 2 * borderWidth
anchors.centerIn: parent
color: borderColor
border.color: borderColor // 设置边界线颜色
border.width: borderWidth // 设置边界线宽度
radius:10
// 电量rect
Rectangle {
id:colorRectiud
width: (batteryContainer.width - 2 * borderWidth)*(batteryLevel)
height: batteryContainer.height - 2 * borderWidth
anchors.verticalCenter: parent.verticalCenter
x: borderWidth
color: colorBasedOnValue(batteryLevel)
radius:5
// 电量颜色获取函数
function colorBasedOnValue(value) {
if (value < 0.1) {
return root.lowerLevelColor;
} else if (value < 0.2) {
return root.lowLevelColor;
} else {
return root.nomalLevelColor; // 默认值或其他颜色
}
}
}
// 电量文字
Text {
anchors.centerIn: parent
text: Math.floor(batteryLevel * 100) + "%"
font.pixelSize: 20
color: "white"
}
}
//电池头
Rectangle {
id: batteryHeader
width: batteryContainer.width / 18
height: batteryContainer.height / 2.5
anchors.left:batteryContainer.right
anchors.verticalCenter: batteryContainer.verticalCenter
color: borderColor
radius: 5
Rectangle {
x: 0
y: 0
width: parent.radius
height: parent.height
radius: 0
color: parent.color
}
}
}
最后, 上面的控件代码需要使用名为 控件名 的 qml 文件包含,如Battery.qml,并将该文件加入资源文件中,入下图所示:
这样我们就使用 qml实现了一个电池控件。
六、控件使用
(1)在使用中,我们需要定义一个Slider控件,使用它来控制电池电量。(与电池控件平级)
(2)再定义一个鼠标点击区域MouseArea,将点击区域填充为电池,点击后设置鼠标为随机电量。(需要被电池控件包含)
(3)电池还有需要电池渐变变化,所以还需要添加一个动画元素,设置电池当前电量到设置电量的渐变。(需要被电池控件包含)
总代码如下图:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 400
height: 400
visible: true
title: "小小电池控件测试"
Battery {
id:batteryID
anchors.centerIn: parent //居中于父对象
PropertyAnimation { //电量变动动画
id:batterChange
target: batteryID
property: "batteryLevel"
duration: 500
easing.type: Easing.InOutQuad
}
// 鼠标点击区域
MouseArea {
anchors.fill: batteryID
onClicked: {
// 模拟电量变化
batterChange.from=batteryID.batteryLevel //设置动画初始值
batterChange.to=Math.random(); //设置动画结束值
batterChange.start(); //启动动画
console.log("batteryLevel changed from "+batterChange.from + " to "+batterChange.to);
}
}
}
Slider {
x:batteryID.x
y:batteryID.y + batteryID.height + 30
from: 0
to: 1
stepSize: 0.01
value:batteryID.batteryLevel
onPositionChanged: {
batteryID.batteryLevel = position;
console.log("Progress Bar Value:", position);
}
}
}