文章的目的为了记录使用QT QML开发学习的经历。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
相关链接:
开源 C++ QT QML 开发(四)复杂控件--Listview
开源 C++ QT QML 开发(五)复杂控件--Gridview
推荐链接:
开源 C# 快速开发(十六)数据库--sqlserver增删改查
本章节主要内容是:圆环进度控件,参数可设置,数据可实时更新。
1.代码分析
2.所有源码
3.效果演示
一、代码分析1. 主程序文件 (main.qml) 分析
ApplicationWindow 主窗口
ApplicationWindow {
id: mainWindow
width: 400
height: 400
title: "圆环进度控件示例"
visible: true
property real currentValue: 0 // 定义当前数值属性,初始为0
property real maxValue: 100 // 定义最大值属性,初始为100
功能: 创建应用程序主窗口,定义了两个关键属性用于数据绑定。
columnlayout
ColumnLayout {
anchors.centerIn: parent // 布局居中于父元素
spacing: 20 // 子元素间距20像素
函数作用: 创建垂直布局,自动管理子元素的位置和大小
戒指
文本
RingProgress {
id: ringProgress
Layout.preferredWidth: 200 // 设置首选宽度
Layout.preferredHeight: 200 // 设置首选高度
currentValue: mainWindow.currentValue // 绑定到主窗口的当前值
maxValue: mainWindow.maxValue // 绑定到主窗口的最大值
backgroundColor: "#f0f0f0" // 设置背景色
ringBackgroundColor: "#e0e0e0" // 设置圆环底色
ringColor: "#4CAF50" // 设置进度圆环颜色
ringWidth: 15 // 设置圆环宽度
}
属性绑定机制: 这里使用了QML的数据绑定,当`mainWindow.currentValue改变时,会自动更新圆环控件。
按钮控制区域
Button {
text: "加10"
onClicked: { // 点击事件处理函数
if (mainWindow.currentValue + 10 <= mainWindow.maxValue) {
mainWindow.currentValue += 10 // 增加值,不超过最大值
} else {
mainWindow.currentValue = mainWindow.maxValue // 达到最大值
}
}
}
函数逻辑:
onClicked: 按钮点击信号的处理函数
条件判断确保数值在有效范围内
直接修改绑定的属性值,触发界面更新
- 自定义圆环控件 (RingProgress.qml) 详细分析
属性定义部分
property real currentValue: 0 // 当前进度值
property real maxValue: 100 // 最大值
property color backgroundColor: "#f0f0f0" // 控件背景色
property color ringBackgroundColor: "#e0e0e0" // 圆环背景色
property color ringColor: "#4CAF50" // 进度圆环颜色
property real ringWidth: 15 // 圆环线条宽度
这些属性提供了控件的可配置接口。
计算属性
property real progress: currentValue / maxValue // 计算进度比例(0-1)
property real startAngle: -90 // 起始角度(从顶部开始)
property real endAngle: startAngle + (progress * 360) // 结束角度
计算原理:
progress: 通过数据绑定自动计算当前进度百分比
endAngle: 根据进度比例计算对应的圆弧结束角度
背景矩形
Rectangle {
id: backgroundRect
anchors.fill: parent // 填充整个父元素
radius: width / 2 // 圆角半径设为宽度一半,形成圆形
color: ringProgress.backgroundColor // 使用配置的背景色
}
函数作用: 创建圆形背景,anchors.fill确保大小自适应。
圆环底色Canvas
Canvas {
id: backgroundCanvas
anchors.fill: parent
antialiasing: true // 开启抗锯齿
onPaint: { // 绘制函数,在需要重绘时自动调用
var ctx = getContext("2d") // 获取2D绘图上下文
ctx.reset() // 重置画布状态
var centerX = width / 2 // 计算中心点X坐标
var centerY = height / 2 // 计算中心点Y坐标
var radius = Math.min(centerX, centerY) - ringWidth / 2 // 计算圆环半径
ctx.beginPath() // 开始绘制路径
ctx.lineWidth = ringWidth // 设置线条宽度
ctx.lineCap = "round" // 设置线条端点样式为圆形
ctx.strokeStyle = ringBackgroundColor // 设置线条颜色
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2) // 绘制完整圆形
ctx.stroke() // 描边绘制
}
}
绘制函数详细分析:
getContext("2d"): 获取HTML5 Canvas风格的2D绘图上下文
ctx.arc(x, y, radius, startAngle, endAngle): 绘制圆弧
参数: 中心坐标(x,y), 半径, 起始角度, 结束角度(弧度制)
Math.PI * 2表示360度,绘制完整圆环
进度圆环Canvas
Canvas {
id: progressCanvas
// ... 类似的属性设置
OnPaint : {
var ctx = getContext (" 2d" )
ctx 。重置()
var Centerx =宽度/ 2
var Centery =高度/ 2
var radius =数学。Min ( Centerx , Centery ) -环宽/ 2
// 角度转换:QML使用度,Canvas使用弧度
var startAngleRad = (startAngle - 90) * Math.PI / 180
var endAngleRad = (endAngle - 90) * Math.PI / 180
CTX 。BeginPath ()
CTX 。线宽=环宽
CTX 。 linecap = "圆形"
CTX 。 strokestyle = ringcolor
ctx.arc(centerX, centerY, radius, startAngleRad, endAngleRad) // 绘制进度圆弧
ctx.stroke()
}
}
关键算法:
角度转换: (角度 - 90) * π / 180
减90度是因为默认
乘以π/180将角度转换为弧度
只绘制从startAngleRad到的圆弧,显示进度endAngleRad
中心文本
Text {
id: centerText
anchors.centerIn: parent // 在父元素中居中
text: Math.round((currentValue / maxValue) * 100) + "%" // 计算百分比文本
font.pixelSize: Math.min(parent.width, parent.height) * 0.25 // 自适应字体大小
font.bold: true
color: "#333333"
}
文本计算:
使用Math.round()四舍五入百分比值
字体大小根据控件尺寸自适应属性变化响应
onCurrentValueChanged: {
progressCanvas.requestPaint() // 请求重绘进度圆环
}
onMaxValueChanged: {
backgroundCanvas.requestPaint() // 重绘底色圆环
progressCanvas.requestPaint() // 重绘进度圆环
}
数据绑定机制:
当属性值改变时,自动调用对应的信号处理函数
requestPaint()通知Canvas需要重新绘制
初始化函数组件。
作用: 组件完成创建后立即执行初始绘制。
- 核心算法总结
圆环绘制算法
半径计算: Math.min(centerX, centerY) - ringWidth / 2
取宽高的最小值确保圆形
减去圆环宽度的一半避免超出边界
角度计算:
起始角度: -
结束角度: -90 + (progress * 360)度
弧度转换: 角度 * π / 180
进度显示:
当progress=0.5(50%)时,绘制从-90度到90度的圆弧,正好是180度
二、所有源码
ringProgress.qml文件源码
import QtQuick 2.12
Item {
id: ringProgress
// 可配置属性
property real currentValue: 0
property real maxValue: 100
property color backgroundColor: "#f0f0f0"
property color ringBackgroundColor: "#e0e0e0"
property color ringColor: "#4CAF50"
property real ringWidth: 15
// 计算属性
property real progress: currentValue / maxValue
property real startAngle: -90 // 从顶部开始
property real endAngle: startAngle + (progress * 360)
width: 200
height: 200
// 背景
Rectangle {
id: backgroundRect
anchors.fill: parent
radius: width / 2
color: ringProgress.backgroundColor
}
// 圆环底色(完整的圆环)
Canvas {
id: backgroundCanvas
anchors.fill: parent
antialiasing: true
onPaint: {
var ctx = getContext("2d")
ctx.reset()
var centerX = width / 2
var centerY = height / 2
var radius = Math.min(centerX, centerY) - ringWidth / 2
ctx.beginPath()
ctx.lineWidth = ringWidth
ctx.lineCap = "round"
ctx.strokeStyle = ringBackgroundColor
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2)
ctx.stroke()
}
}
// 进度圆环
Canvas {
id: progressCanvas
anchors.fill: parent
antialiasing: true
onPaint: {
var ctx = getContext("2d")
ctx.reset()
var centerX = width / 2
var centerY = height / 2
var radius = Math.min(centerX, centerY) - ringWidth / 2
// 转换为弧度
var startAngleRad = (startAngle - 90) * Math.PI / 180
var endAngleRad = (endAngle - 90) * Math.PI / 180
ctx.beginPath()
ctx.lineWidth = ringWidth
ctx.lineCap = "round"
ctx.strokeStyle = ringColor
ctx.arc(centerX, centerY, radius, startAngleRad, endAngleRad)
ctx.stroke()
}
}
// 中心文本
Text {
id: centerText
anchors.centerIn: parent
text: Math.round((currentValue / maxValue) * 100) + "%"
font.pixelSize: Math.min(parent.width, parent.height) * 0.25
font.bold: true
color: "#333333"
}
// 当属性改变时重绘Canvas
onCurrentValueChanged: {
progressCanvas.requestPaint()
}
onMaxValueChanged: {
backgroundCanvas.requestPaint()
progressCanvas.requestPaint()
}
onRingWidthChanged: {
backgroundCanvas.requestPaint()
progressCanvas.requestPaint()
}
onRingBackgroundColorChanged: {
backgroundCanvas.requestPaint()
}
onRingColorChanged: {
progressCanvas.requestPaint()
}
Component.onCompleted: {
backgroundCanvas.requestPaint()
progressCanvas.requestPaint()
}
}
main.qml文件源码
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
ApplicationWindow {
id: mainWindow
width: 400
height: 400
title: "圆环进度控件示例"
visible: true
property real currentValue: 0
property real maxValue: 100
ColumnLayout {
anchors.centerIn: parent
spacing: 20
// 圆环进度控件
RingProgress {
id: ringProgress
Layout.preferredWidth: 200
Layout.preferredHeight: 200
currentValue: mainWindow.currentValue
maxValue: mainWindow.maxValue
backgroundColor: "#f0f0f0"
ringBackgroundColor: "#E6F7FF" // 非常浅的天蓝色
ringColor: "#00BFFF" // 深天蓝色
ringWidth: 15
}
// 按钮控制区域
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: 10
Button {
text: "加10"
onClicked: {
if (mainWindow.currentValue + 10 <= mainWindow.maxValue) {
mainWindow.currentValue += 10
} else {
mainWindow.currentValue = mainWindow.maxValue
}
}
}
Button {
text: "减10"
onClicked: {
if (mainWindow.currentValue - 10 >= 0) {
mainWindow.currentValue -= 10
} else {
mainWindow.currentValue = 0
}
}
}
}
// 显示当前数值
Text {
Layout.alignment: Qt.AlignHCenter
text: "当前值: " + mainWindow.currentValue
font.pixelSize: 16
}
}
}
三、效果演示
运行后点击按钮,实时更新圆环值,打印当前圆环值。
