簡介

本文是《Qml組件化編程》系列文章的第六篇,濤哥將教大家,進度條組件的定製。


順便說一下,濤哥的TaoQuick項目正式開源了, 系列文章中的所有功能,包括動態換皮膚、切換多語言等等,都集成在了TaoQuick中,

同時濤哥也在TaoQuick中使用了持續集成(CI)技術,目前已經能夠自動編譯、發布Windows和 Macos平臺的軟體包,可以在github的Release界面下載體驗。

互聯網行業很流行的DevOps理念,在TaoQuick項目中得到了最佳的實踐。

(linux平臺的發布工具linuxdeployqt暫時還有點問題,濤哥後續會搞定的)

地址在這github.com/jaredtao/Tao, 趕快去star吧。


註:文章主要發布在濤哥的博客 和 知乎專欄-濤哥的Qt進階之路

先看預覽圖

新的漸變效果

Qt 5.12 加入了新的漸變效果,一共180種,效果來自這個網站https://webgradients.com

按照幫助文檔的介紹,可以通過下面這兩種方式使用

Rectangle {
y: 0; width: 80; height: 80
gradient: Gradient.NightFade
}

Rectangle {
y: 0; width: 80; height: 80
gradient: "NightFade"
}

濤哥立即想到了,枚舉不就是數字嘛

Rectangle {
y: 0; width: 80; height: 80
gradient: 1
}
Rectangle {
y: 0; width: 80; height: 80
gradient: 2
}
Rectangle {
y: 0; width: 80; height: 80
gradient: 3
}

試了一下,這樣也是可以啊,哈哈。

於是濤哥就把180種漸變效果都拉出來看看。

Qt只支持水平和垂直的漸變,其中有小部分是不能用的,所以只有165個能用。

看一下展示全部漸變的Qml代碼:

import QtQuick 2.9
import QtQuick.Controls 2.5

Item {
anchors.fill: parent

GridView {
id: g
anchors.fill: parent
anchors.margins: 20
cellWidth: 160
cellHeight: 160
model: 180 //這裡的數據Model直接給個數字180
clip: true
property var invalidList: [27, 39, 40, 45, 71, 74, 105, 111, 119, 130, 135, 141] //這幾個是不能用的,看過運行報錯後手動列出來的。
delegate: Item{
width: 160
height: 160
Rectangle{
width: 150
height: 150
anchors.centerIn: parent
color: "white"
radius: 10
Text {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 2
text: index + 1
}
Rectangle {
width: 100
height: width
radius: width / 2
//編號在列表裡的,直接漸變賦值為null,就不會在Qml運行時報警告了
gradient: g.invalidList.indexOf(modelData + 1) < 0 ? modelData + 1 : null
anchors.centerIn: parent
anchors.verticalCenterOffset: 10
}
}
}
}
}

條形進度條

普通進度條的原理,就是有一個比較長的矩形做背景,在上面放一個顏色不同的矩形,其寬度跟著百分比變化,

100%時寬度與背景一致。

可以寫一個很簡要的進度條。

Rectangle {
id: back
width: 300
height: 50
radius: height / 2
color: "white"
Rectangle {
id: front
//寬度是 背景寬度 * 百分比
width: percent / 100 * parent.width
height: parent.height
radius: parent.radius
color: "red"
}
}

再添加一點元素,在右側放一個文本,表示百分比,或者放圖片。甚至給進度條加個閃光特效。

經過一系列的加工,封裝成一個綜合的組件,最終結果如下:

//NormalProgressBar.qml

import QtQuick 2.12
import QtQuick.Controls 2.12
Item {
id: r
property int percent: 0
implicitWidth: 200
implicitHeight: 16
//枚舉, 表示右側Bar的類型
enum BarType {
Text, //右側放文本
SucceedOrFailed, //右側放圖片表示成功和失敗,沒有100%就是失敗
NoBar //右側不放東西
}
//只讀屬性,內置一些顏色
readonly property color __backColor: "#f5f5f5"
readonly property color __blueColor: "#1890ff"
readonly property color __succeedColor: "#52c41a"
readonly property color __failedColor: "#f5222d"

//背景色,默認值
property color backgroundColor: __backColor
//前景色
property color frontColor: {
switch (barType) {
case TNormalProgress.BarType.SucceedOrFailed:
return percent === 100 ? __succeedColor : __failedColor
default:
return __blueColor
}
}
//文字
property string text: String("%1%").arg(percent)
//漸變 0-180 除掉不能用的,165種漸變任你選
property int gradientIndex: -1
//閃爍特效
property bool flicker: false
//右側Bar類型
property var barType: TNormalProgress.BarType.Text
Text {
id: t
enabled: barType === TNormalProgress.BarType.Text
visible: enabled
text: r.text
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
}
Image {
id: image
source: percent === 100 ? "qrc:/Core/Image/ProgressBar/ok_circle.png" : "qrc:/Core/Image/ProgressBar/fail_circle.png"
height: parent.height
width: height
enabled: barType === TNormalProgress.BarType.SucceedOrFailed
visible: enabled
anchors.right: parent.right
}

property var __right: {
switch (barType) {
case TNormalProgress.BarType.Text:
return t.left
case TNormalProgress.BarType.SucceedOrFailed:
return image.left
default:
return r.right
}
}
Rectangle { //背景
id: back
anchors.left: parent.left
anchors.right: __right
anchors.rightMargin: 4
height: parent.height
radius: height / 2
color: backgroundColor
Rectangle { //前景
id: front
width: percent / 100 * parent.width
height: parent.height
radius: parent.radius
color: frontColor
gradient: gradientIndex === -1 ? null : gradientIndex
Rectangle { //前景上的閃光特效
id: flick
height: parent.height
width: 0
radius: parent.radius
color: Qt.lighter(parent.color, 1.2)
enabled: flicker
visible: enabled
NumberAnimation on width {
running: visible
from: 0
to: front.width
duration: 1000
loops: Animation.Infinite;
}
}
}
}
}

圓形進度條

將一個Rectangle做成圓形: 寬高相等,半徑為寬度一半。

再把 顏色設置為透明,邊框不透明,邊框加粗一點,就是一個圓環了。

Rectangle {
id: back
width: 120
height: width
radius: width / 2
color: "transparent"
border.width: 10
border.color: "white"
}

接下來給圓環貼上一個圓形漸變色,漸變按照百分比來做。

import QtGraphicalEffects 1.12
Rectangle {
id: back
width: 120
height: width
radius: width / 2
color: "transparent"
border.width: 10
border.color: "white"

ConicalGradient {
anchors.fill: back
source: back
gradient: Gradient {
GradientStop { position: 0.0; color: "white" }
GradientStop { position: percent / 100 ; color: "red" }
GradientStop { position: percent / 100 + 0.001; color: "white" }
GradientStop { position: 1.0; color: "white" }
}
}
}

漸變從0 到 percent處都是有漸變顏色的, 再從percent + 0.001 到1.0處,都是背景色,這樣就是一個簡易的圓形進度條了。

不過這裡percent為100的情況,圓形漸變處理不了,我們可以特殊處理,直接讓背景圓環變成前景色就行了。(既然都100%了,背景肯定是全部被遮住了,那就讓背景做前景,藏掉真正的前景)

```qml
import QtGraphicalEffects 1.12
Rectangle {
id: back
width: 120
height: width
radius: width / 2
color: "transparent"
border.width: 10
border.color: percent === 100 ? "red" : "white" //百分比為100時顯示為前景,否則顯示為背景

ConicalGradient {
anchors.fill: back
source: back
enabled: percent != 100 //百分比不為100時有效
visible: enabled //百分比不為100時有效
gradient: Gradient {
GradientStop { position: 0.0; color: "white" }
GradientStop { position: percent / 100 ; color: "red" }
GradientStop { position: percent / 100 + 0.001; color: "white" }
GradientStop { position: 1.0; color: "white" }
}
}
}

再加點料,封裝成組件

//CircleProgressBar.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtGraphicalEffects 1.12
Item {
id: r
property int percent: 0

enum BarType {
Text,
SucceedOrFailed,
NoBar
}
readonly property color __backColor: "#f5f5f5"
readonly property color __blueColor: "#1890ff"
readonly property color __succeedColor: "#52c41a"
readonly property color __failedColor: "#f5222d"
property color backgroundColor: __backColor
property color frontColor: {
switch (barType) {
case TNormalProgress.BarType.SucceedOrFailed:
return percent === 100 ? __succeedColor : __failedColor
default:
return __blueColor
}
}
property string text: String("%1%").arg(percent)
property var barType: TNormalProgress.BarType.Text
Rectangle {
id: back
color: "transparent"
anchors.fill: parent
border.color: percent === 100 ? frontColor : backgroundColor
border.width: 10
radius: width / 2
}
Text {
id: t
enabled: barType === TNormalProgress.BarType.Text
visible: enabled
text: r.text
anchors.centerIn: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
Image {
id: image
source: percent === 100 ? "qrc:/Core/Image/ProgressBar/ok.png" : "qrc:/Core/Image/ProgressBar/fail.png"
enabled: barType === TNormalProgress.BarType.SucceedOrFailed
visible: enabled
scale: 2
anchors.centerIn: parent
}
ConicalGradient {
anchors.fill: back
source: back
enabled: percent != 100
visible: enabled
smooth: true
antialiasing: true
gradient: Gradient {
GradientStop { position: 0.0; color: frontColor }
GradientStop { position: percent / 100 ; color: frontColor }
GradientStop { position: percent / 100 + 0.001; color: backgroundColor }
GradientStop { position: 1.0; color: backgroundColor }
}
}
}

最後,來個合影

Item {
id: r
anchors.fill: parent
Grid {
id: g
anchors.fill: parent
anchors.margins: 10
columns: 2
spacing: 10
Column {
width: g.width / 2 - 10
height: g.height /2 - 10
spacing: 10
TNormalProgress {
width: parent.width
backgroundColor: gConfig.reserverColor
NumberAnimation on percent { from: 0; to: 100; duration: 5000; running: true; loops: Animation.Infinite}
}
TNormalProgress {
width: parent.width
backgroundColor: gConfig.reserverColor
flicker: true
percent: 50
}
TNormalProgress {
width: parent.width
backgroundColor: gConfig.reserverColor
barType: TNormalProgress.BarType.SucceedOrFailed
percent: 70
}
TNormalProgress {
width: parent.width
backgroundColor: gConfig.reserverColor
barType: TNormalProgress.BarType.SucceedOrFailed
percent: 100
}
TNormalProgress {
width: parent.width
backgroundColor: gConfig.reserverColor
barType: TNormalProgress.BarType.NoBar
percent: 50
gradientIndex: 12
}
}
Row {
width: g.width / 2 - 10
height: g.height /2 - 10
spacing: 10

TCircleProgress {
width: 120
height: 120
backgroundColor: gConfig.reserverColor
NumberAnimation on percent { from: 0; to: 100; duration: 5000; running: true; loops: Animation.Infinite}
}
TCircleProgress {
width: 120
height: 120
backgroundColor: gConfig.reserverColor
barType: TNormalProgress.BarType.SucceedOrFailed
percent: 75
}
TCircleProgress {
width: 120
height: 120
backgroundColor: gConfig.reserverColor
barType: TNormalProgress.BarType.SucceedOrFailed
percent: 100
}
}
Row {
width: g.width / 2 - 10
height: g.height /2 - 10
spacing: 10

TCircleProgress {
width: 120
height: 120
backgroundColor: gConfig.reserverColor
text: String("%1天").arg(percent)
NumberAnimation on percent { from: 0; to: 100; duration: 5000; running: true; loops: Animation.Infinite}
}
TCircleProgress {
id: ppppp
width: 120
height: 120
backgroundColor: gConfig.reserverColor
barType: TNormalProgress.BarType.SucceedOrFailed
SequentialAnimation {
running: true
loops: Animation.Infinite
NumberAnimation {
target: ppppp
property: "percent"
from: 0
to: 100
duration: 3000
}
PauseAnimation {
duration: 500
}
}
}
TCircleProgress {
width: 120
height: 120
backgroundColor: gConfig.reserverColor
percent: 100
}
}
Column {
width: g.width / 2 - 10
height: g.height /2 - 10
spacing: 10
}
Column {
width: g.width / 2 - 10
height: g.height /2 - 10
spacing: 10
}
}

}

效果如下:

轉載聲明

文章出自濤哥的博客

文章採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可, 轉載請註明出處, 謝謝合作 ? 濤哥

聯繫方式


作者 濤哥

開發理念 弘揚魯班文化,傳承工匠精神

博客

武威濤哥的博客?

jaredtao.github.io

github

jaredtao - Overview?

github.com
圖標

郵箱[email protected]

微信xsd2410421

QQ759378563

請放心聯繫我,樂於提供諮詢服務,也可洽談商務合作相關事宜。

如果覺得濤哥寫的還不錯,還請為濤哥打個賞,您的讚賞是濤哥持續創作的源泉。

推薦閱讀:

相關文章