• 2599阅读
  • 3回复

Qml组件化编程6-进度条定制 [复制链接]

上一主题 下一主题
离线dd759378563
 

只看楼主 倒序阅读 楼主  发表于: 2019-05-18

简介

本文是《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
按照帮助文档的介绍,可以通过下面这两种方式使用
  1. Rectangle {
  2.       y: 0; width: 80; height: 80
  3.       gradient: Gradient.NightFade
  4.   }
  5.   Rectangle {
  6.       y: 0; width: 80; height: 80
  7.       gradient: "NightFade"
  8.   }

  
涛哥立即想到了,枚举不就是数字嘛
  1. Rectangle {
  2.       y: 0; width: 80; height: 80
  3.       gradient: 1
  4.   }
  5.   Rectangle {
  6.       y: 0; width: 80; height: 80
  7.       gradient: 2
  8.   }
  9.   Rectangle {
  10.       y: 0; width: 80; height: 80
  11.       gradient: 3
  12.   }



试了一下,这样也是可以啊,哈哈。
于是涛哥就把180种渐变效果都拉出来看看。

Qt只支持水平和垂直的渐变,其中有小部分是不能用的,所以只有165个能用。
看一下展示全部渐变的Qml代码:
  1. import QtQuick 2.9
  2. import QtQuick.Controls 2.5
  3. Item {
  4.     anchors.fill: parent
  5.     GridView {
  6.         id: g
  7.         anchors.fill: parent
  8.         anchors.margins: 20
  9.         cellWidth: 160
  10.         cellHeight: 160
  11.         model: 180          //这里的数据Model直接给个数字180
  12.         clip: true
  13.         property var invalidList: [27, 39, 40, 45, 71, 74, 105, 111, 119, 130, 135, 141]    //这几个是不能用的,看过运行报错后手动列出来的。
  14.         delegate: Item{
  15.             width: 160
  16.             height: 160
  17.             Rectangle{
  18.                 width: 150
  19.                 height: 150
  20.                 anchors.centerIn: parent
  21.                 color: "white"
  22.                 radius: 10
  23.                 Text {
  24.                     anchors.horizontalCenter: parent.horizontalCenter
  25.                     anchors.top: parent.top
  26.                     anchors.topMargin: 2
  27.                     text: index + 1
  28.                 }
  29.                 Rectangle {
  30.                     width: 100
  31.                     height: width
  32.                     radius:  width / 2
  33.                     //编号在列表里的,直接渐变赋值为null,就不会在Qml运行时报警告了
  34.                     gradient: g.invalidList.indexOf(modelData + 1) < 0 ? modelData + 1 : null
  35.                     anchors.centerIn: parent
  36.                     anchors.verticalCenterOffset: 10
  37.                 }
  38.             }
  39.         }
  40.     }
  41. }




条形进度条

普通进度条的原理,就是有一个比较长的矩形做背景,在上面放一个颜色不同的矩形,其宽度跟着百分比变化,
100%时宽度与背景一致。
可以写一个很简要的进度条。
  1. Rectangle {
  2.     id: back
  3.     width: 300
  4.     height: 50
  5.     radius: height / 2
  6.     color: "white"  
  7.     property int percent: 0
  8.     Rectangle {
  9.         id: front
  10.         //宽度是 背景宽度 * 百分比
  11.         width: percent / 100 * parent.width  
  12.         height: parent.height
  13.         radius: parent.radius
  14.         color: "red"
  15.     }
  16. }



再添加一点元素,在右侧放一个文本,表示百分比,或者放图片。甚至给进度条加个闪光特效。
经过一系列的加工,封装成一个综合的组件,最终结果如下:
  1. //NormalProgressBar.qml
  2. import QtQuick 2.12
  3. import QtQuick.Controls 2.12
  4. Item {
  5.     id: r
  6.     property int percent: 0
  7.     implicitWidth: 200
  8.     implicitHeight: 16
  9.     //枚举, 表示右侧Bar的类型
  10.     enum BarType {  
  11.         Text,               //右侧放文本
  12.         SucceedOrFailed,    //右侧放图片表示成功和失败,没有100%就是失败
  13.         NoBar               //右侧不放东西
  14.     }
  15.     //只读属性,内置一些颜色
  16.     readonly property color __backColor: "#f5f5f5"
  17.     readonly property color __blueColor: "#1890ff"
  18.     readonly property color __succeedColor: "#52c41a"
  19.     readonly property color __failedColor: "#f5222d"
  20.     //背景色,默认值
  21.     property color backgroundColor: __backColor
  22.     //前景色
  23.     property color frontColor: {
  24.         switch (barType) {
  25.         case TNormalProgress.BarType.SucceedOrFailed:
  26.             return percent === 100 ? __succeedColor : __failedColor
  27.         default:
  28.             return __blueColor
  29.         }
  30.     }
  31.     //文字
  32.     property string text: String("%1%").arg(percent)
  33.     //渐变 0-180 除掉不能用的,165种渐变任你选
  34.     property int gradientIndex: -1
  35.     //闪烁特效
  36.     property bool flicker: false
  37.     //右侧Bar类型
  38.     property var barType: TNormalProgress.BarType.Text
  39.     Text {
  40.         id: t
  41.         enabled: barType === TNormalProgress.BarType.Text
  42.         visible: enabled
  43.         text: r.text
  44.         anchors.verticalCenter: parent.verticalCenter
  45.         anchors.right: parent.right
  46.     }
  47.     Image {
  48.         id: image
  49.         source: percent === 100 ? "qrc:/Core/Image/ProgressBar/ok_circle.png" : "qrc:/Core/Image/ProgressBar/fail_circle.png"
  50.         height: parent.height
  51.         width: height
  52.         enabled: barType === TNormalProgress.BarType.SucceedOrFailed
  53.         visible: enabled
  54.         anchors.right: parent.right
  55.     }
  56.     property var __right: {
  57.         switch (barType) {
  58.         case TNormalProgress.BarType.Text:
  59.             return t.left
  60.         case TNormalProgress.BarType.SucceedOrFailed:
  61.             return image.left
  62.         default:
  63.             return r.right
  64.         }
  65.     }
  66.     Rectangle {                             //背景
  67.         id: back
  68.         anchors.left: parent.left
  69.         anchors.right: __right
  70.         anchors.rightMargin: 4
  71.         height: parent.height
  72.         radius: height / 2
  73.         color: backgroundColor
  74.         Rectangle {                         //前景
  75.             id: front
  76.             width: percent / 100 * parent.width
  77.             height: parent.height
  78.             radius: parent.radius
  79.             color: frontColor
  80.             gradient: gradientIndex === -1 ? null : gradientIndex
  81.             Rectangle {                     //前景上的闪光特效
  82.                 id: flick
  83.                 height: parent.height
  84.                 width: 0
  85.                 radius: parent.radius
  86.                 color: Qt.lighter(parent.color, 1.2)
  87.                 enabled: flicker
  88.                 visible: enabled
  89.                 NumberAnimation on width {
  90.                     running: visible
  91.                     from: 0
  92.                     to: front.width
  93.                     duration: 1000
  94.                     loops: Animation.Infinite;
  95.                 }
  96.             }
  97.         }
  98.     }
  99. }



圆形进度条

将一个Rectangle做成圆形: 宽高相等,半径为宽度一半。
再把 颜色设置为透明,边框不透明,边框加粗一点,就是一个圆环了。
  1. Rectangle {
  2.     id: back
  3.     width: 120
  4.     height: width
  5.     radius: width / 2
  6.     color: "transparent"
  7.     border.width: 10
  8.     border.color: "white"
  9. }



接下来给圆环贴上一个圆形渐变色,渐变按照百分比来做。
  1. import QtGraphicalEffects 1.12
  2. Rectangle {
  3.     id: back
  4.     width: 120
  5.     height: width
  6.     radius: width / 2
  7.     color: "transparent"
  8.     border.width: 10
  9.     border.color: "white"
  10.     property int percent: 0
  11.     ConicalGradient {
  12.         anchors.fill: back
  13.         source: back
  14.         gradient: Gradient {
  15.             GradientStop { position: 0.0; color: "white" }
  16.             GradientStop { position: percent / 100 ; color: "red" }
  17.             GradientStop { position: percent / 100 + 0.001; color: "white" }
  18.             GradientStop { position: 1.0; color: "white" }
  19.         }
  20.     }
  21. }



渐变从0 到 percent处都是有渐变颜色的, 再从percent + 0.001 到1.0处,都是背景色,这样就是一个简易的圆形进度条了。
不过这里percent为100的情况,圆形渐变处理不了,我们可以特殊处理,直接让背景圆环变成前景色就行了。(既然都100%了,背景肯定是全部被遮住了,那就让背景做前景,藏掉真正的前景)
  1. import QtGraphicalEffects 1.12
  2. Rectangle {
  3.     id: back
  4.     width: 120
  5.     height: width
  6.     radius: width / 2
  7.     color: "transparent"
  8.     border.width: 10
  9.     border.color: percent === 100 ? "red" : "white"     //百分比为100时显示为前景,否则显示为背景
  10.     property int percent: 0
  11.     ConicalGradient {
  12.         anchors.fill: back
  13.         source: back
  14.         enabled: percent != 100     //百分比不为100时有效
  15.         visible: enabled            //百分比不为100时有效
  16.         gradient: Gradient {
  17.             GradientStop { position: 0.0; color: "white" }
  18.             GradientStop { position: percent / 100 ; color: "red" }
  19.             GradientStop { position: percent / 100 + 0.001; color: "white" }
  20.             GradientStop { position: 1.0; color: "white" }
  21.         }
  22.     }
  23. }



再加点料,封装成组件
  1. //CircleProgressBar.qml
  2. import QtQuick 2.12
  3. import QtQuick.Controls 2.12
  4. import QtGraphicalEffects 1.12
  5. Item {
  6.     id: r
  7.     property int percent: 0
  8.     enum BarType {
  9.         Text,
  10.         SucceedOrFailed,
  11.         NoBar
  12.     }
  13.     readonly property color __backColor: "#f5f5f5"
  14.     readonly property color __blueColor: "#1890ff"
  15.     readonly property color __succeedColor: "#52c41a"
  16.     readonly property color __failedColor: "#f5222d"
  17.     property color backgroundColor: __backColor
  18.     property color frontColor: {
  19.         switch (barType) {
  20.         case TNormalProgress.BarType.SucceedOrFailed:
  21.             return percent === 100 ? __succeedColor : __failedColor
  22.         default:
  23.             return __blueColor
  24.         }
  25.     }
  26.     property string text: String("%1%").arg(percent)
  27.     property var barType: TNormalProgress.BarType.Text
  28.     Rectangle {
  29.         id: back
  30.         color: "transparent"
  31.         anchors.fill: parent
  32.         border.color: percent === 100 ? frontColor : backgroundColor
  33.         border.width: 10
  34.         radius: width / 2
  35.     }
  36.     Text {
  37.         id: t
  38.         enabled: barType === TNormalProgress.BarType.Text
  39.         visible: enabled
  40.         text: r.text
  41.         anchors.centerIn: parent
  42.         verticalAlignment: Text.AlignVCenter
  43.         horizontalAlignment: Text.AlignHCenter
  44.     }
  45.     Image {
  46.         id: image
  47.         source: percent === 100 ? "qrc:/Core/Image/ProgressBar/ok.png" : "qrc:/Core/Image/ProgressBar/fail.png"
  48.         enabled: barType === TNormalProgress.BarType.SucceedOrFailed
  49.         visible: enabled
  50.         scale: 2
  51.         anchors.centerIn: parent
  52.     }
  53.     ConicalGradient {
  54.         anchors.fill: back
  55.         source: back
  56.         enabled: percent != 100
  57.         visible: enabled
  58.         smooth: true
  59.         antialiasing: true
  60.         gradient: Gradient {
  61.             GradientStop { position: 0.0; color: frontColor }
  62.             GradientStop { position: percent / 100 ; color: frontColor }
  63.             GradientStop { position: percent / 100 + 0.001; color: backgroundColor }
  64.             GradientStop { position: 1.0; color: backgroundColor }
  65.         }
  66.     }
  67. }


最后来个合影


  1. Item {
  2.     id: r
  3.     anchors.fill: parent
  4.     Grid {
  5.         id: g
  6.         anchors.fill: parent
  7.         anchors.margins: 10
  8.         columns: 2
  9.         spacing: 10
  10.         Column {
  11.             width: g.width / 2 - 10
  12.             height: g.height /2 - 10
  13.             spacing: 10
  14.             TNormalProgress {
  15.                 width: parent.width
  16.                 backgroundColor: gConfig.reserverColor
  17.                 NumberAnimation on percent { from: 0; to: 100; duration: 5000; running: true; loops: Animation.Infinite}
  18.             }
  19.             TNormalProgress {
  20.                 width: parent.width
  21.                 backgroundColor: gConfig.reserverColor
  22.                 flicker: true
  23.                 percent: 50
  24.             }
  25.             TNormalProgress {
  26.                 width: parent.width
  27.                 backgroundColor: gConfig.reserverColor
  28.                 barType: TNormalProgress.BarType.SucceedOrFailed
  29.                 percent: 70
  30.             }
  31.             TNormalProgress {
  32.                 width: parent.width
  33.                 backgroundColor: gConfig.reserverColor
  34.                 barType: TNormalProgress.BarType.SucceedOrFailed
  35.                 percent: 100
  36.             }
  37.             TNormalProgress {
  38.                 width: parent.width
  39.                 backgroundColor: gConfig.reserverColor
  40.                 barType: TNormalProgress.BarType.NoBar
  41.                 percent: 50
  42.                 gradientIndex: 12
  43.             }
  44.         }
  45.         Row {
  46.             width: g.width / 2 - 10
  47.             height: g.height /2 - 10
  48.             spacing: 10
  49.             TCircleProgress {
  50.                 width: 120
  51.                 height: 120
  52.                 backgroundColor: gConfig.reserverColor
  53.                 NumberAnimation on percent { from: 0; to: 100; duration: 5000; running: true; loops: Animation.Infinite}
  54.             }
  55.             TCircleProgress {
  56.                 width: 120
  57.                 height: 120
  58.                 backgroundColor: gConfig.reserverColor
  59.                 barType: TNormalProgress.BarType.SucceedOrFailed
  60.                 percent: 75
  61.             }
  62.             TCircleProgress {
  63.                 width: 120
  64.                 height: 120
  65.                 backgroundColor: gConfig.reserverColor
  66.                 barType: TNormalProgress.BarType.SucceedOrFailed
  67.                 percent: 100
  68.             }
  69.         }
  70.         Row {
  71.             width: g.width / 2 - 10
  72.             height: g.height /2 - 10
  73.             spacing: 10
  74.             TCircleProgress {
  75.                 width: 120
  76.                 height: 120
  77.                 backgroundColor: gConfig.reserverColor
  78.                 text: String("%1天").arg(percent)
  79.                 NumberAnimation on percent { from: 0; to: 100; duration: 5000; running: true; loops: Animation.Infinite}
  80.             }
  81.             TCircleProgress {
  82.                 id: ppppp
  83.                 width: 120
  84.                 height: 120
  85.                 backgroundColor: gConfig.reserverColor
  86.                 barType: TNormalProgress.BarType.SucceedOrFailed
  87.                 SequentialAnimation {
  88.                     running: true
  89.                     loops: Animation.Infinite
  90.                     NumberAnimation {
  91.                         target: ppppp
  92.                         property: "percent"
  93.                         from: 0
  94.                         to: 100
  95.                         duration: 3000
  96.                     }
  97.                     PauseAnimation {
  98.                         duration: 500
  99.                     }
  100.                 }
  101.             }
  102.             TCircleProgress {
  103.                 width: 120
  104.                 height: 120
  105.                 backgroundColor: gConfig.reserverColor
  106.                 percent: 100
  107.             }
  108.         }
  109.     }
  110. }





涛哥是个Qml高手,著有《Qml组件化编程》《Qml特效》系列教程,见知乎专栏-Qt进阶之路:https://zhuanlan.zhihu.com/TaoQt
或微信公众号:Qt进阶之路
离线dd759378563

只看该作者 1楼 发表于: 2019-05-18
代码格式已经修复
涛哥是个Qml高手,著有《Qml组件化编程》《Qml特效》系列教程,见知乎专栏-Qt进阶之路:https://zhuanlan.zhihu.com/TaoQt
或微信公众号:Qt进阶之路
离线liudianwu

只看该作者 2楼 发表于: 2019-05-18
qml效果真是炫
欢迎关注微信公众号:Qt实战 (各种开源作品、经验整理、项目实战技巧,专注Qt/C++软件开发,视频监控、物联网、工业控制、嵌入式软件、国产化系统应用软件开发)QQ:517216493  WX:feiyangqingyun  QQ群:751439350
离线big_mouse

只看该作者 3楼 发表于: 2020-04-15
快速回复
限100 字节
 
上一个 下一个