本文是《Qml組件化編程》系列文章的第六篇,濤哥將教大家,進度條組件的定製。
順便說一下,濤哥的TaoQuick項目正式開源了, 系列文章中的所有功能,包括動態換皮膚、切換多語言等等,都集成在了TaoQuick中,
同時濤哥也在TaoQuick中使用了持續集成(CI)技術,目前已經能夠自動編譯、發布Windows和 Macos平臺的軟體包,可以在github的Release界面下載體驗。
互聯網行業很流行的DevOps理念,在TaoQuick項目中得到了最佳的實踐。
(linux平臺的發布工具linuxdeployqt暫時還有點問題,濤哥後續會搞定的)
地址在這https://github.com/jaredtao/TaoQuick, 趕快去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 國際許可協議進行許可, 轉載請註明出處, 謝謝合作 ? 濤哥
作者 濤哥
開發理念 弘揚魯班文化,傳承工匠精神
博客
github
郵箱[email protected]
微信xsd2410421
QQ759378563
請放心聯繫我,樂於提供諮詢服務,也可洽談商務合作相關事宜。
推薦閱讀: