Progress Circle with QML and Canvas

progress-circle

Are you looking for an easy way to implement a fully customizable, nicely animated progress circle in QML?

This is the way to go:

Use a canvas control to paint the arc and a full circle as a background. You can set the size of the control, colort and the start and end angle of the arc. If you change the angles, the change will be animated – of course, you can turn the animation off. If isPie set to true, a pie segment is painted instead of an animation.

ProgressCircle.cml:


// ByteBau (Jörn Buchholz) @bytebau.com

import QtQuick 2.0
import QtQml 2.2

Item {
    id: root

    width: size
    height: size

    property int size: 200               // The size of the circle in pixel
    property real arcBegin: 0            // start arc angle in degree
    property real arcEnd: 270            // end arc angle in degree
    property real arcOffset: 0           // rotation
    property bool isPie: false           // paint a pie instead of an arc
    property bool showBackground: false  // a full circle as a background of the arc
    property real lineWidth: 20          // width of the line
    property string colorCircle: "#CC3333"
    property string colorBackground: "#779933"

    property alias beginAnimation: animationArcBegin.enabled
    property alias endAnimation: animationArcEnd.enabled

    property int animationDuration: 200

    onArcBeginChanged: canvas.requestPaint()
    onArcEndChanged: canvas.requestPaint()

    Behavior on arcBegin {
       id: animationArcBegin
       enabled: true
       NumberAnimation {
           duration: root.animationDuration
           easing.type: Easing.InOutCubic
       }
    }

    Behavior on arcEnd {
       id: animationArcEnd
       enabled: true
       NumberAnimation {
           duration: root.animationDuration
           easing.type: Easing.InOutCubic
       }
    }

    Canvas {
        id: canvas
        anchors.fill: parent
        rotation: -90 + parent.arcOffset

        onPaint: {
            var ctx = getContext("2d")
            var x = width / 2
            var y = height / 2
            var start = Math.PI * (parent.arcBegin / 180)
            var end = Math.PI * (parent.arcEnd / 180)
            ctx.reset()

            if (root.isPie) {
                if (root.showBackground) {
                    ctx.beginPath()
                    ctx.fillStyle = root.colorBackground
                    ctx.moveTo(x, y)
                    ctx.arc(x, y, width / 2, 0, Math.PI * 2, false)
                    ctx.lineTo(x, y)
                    ctx.fill()
                }
                ctx.beginPath()
                ctx.fillStyle = root.colorCircle
                ctx.moveTo(x, y)
                ctx.arc(x, y, width / 2, start, end, false)
                ctx.lineTo(x, y)
                ctx.fill()
            } else {
                if (root.showBackground) {
                    ctx.beginPath();
                    ctx.arc(x, y, (width / 2) - parent.lineWidth / 2, 0, Math.PI * 2, false)
                    ctx.lineWidth = root.lineWidth
                    ctx.strokeStyle = root.colorBackground
                    ctx.stroke()
                }
                ctx.beginPath();
                ctx.arc(x, y, (width / 2) - parent.lineWidth / 2, start, end, false)
                ctx.lineWidth = root.lineWidth
                ctx.strokeStyle = root.colorCircle
                ctx.stroke()
            }
        }
    }
}

To use the component like in the picture above, just place it inside a layout container like this:


Row {
    anchors.centerIn: parent
    spacing: 10

    ProgressCircle {
        size: 160
        colorCircle: "#0092CC"
        colorBackground: "#E6E6E6"
        arcBegin: 0
        arcEnd: 270
        lineWidth: 10
    }

    ProgressCircle {
        size: 160
        colorCircle: "#FF3333"
        colorBackground: "#E6E6E6"
         showBackground: true
         arcBegin: 0
         arcEnd: 220
    }

    ProgressCircle {
        size: 160
        colorCircle: "#779933"
        colorBackground: "#E6E6E6"
         showBackground: true
        isPie: true
        arcBegin: 90
        arcEnd: 200
    }
}

 

3 thoughts on “Progress Circle with QML and Canvas

Leave a Reply to mmjvox Cancel reply

*