How To Create A Circular Progress Bar In Pure Qml+js?
Solution 1:
I've implemented a basic circular progress using a Canvas.
import QtQml 2.2import QtQuick 2.0// draws two arcs (portion of a circle)// fills the circle with a lighter secondary color// when pressed
Canvas {
id: canvas
width: 240
height: 240
antialiasing: true
property color primaryColor: "orange"
property color secondaryColor: "lightblue"
property real centerWidth: width / 2
property real centerHeight: height / 2
property real radius: Math.min(canvas.width, canvas.height) / 2
property real minimumValue: 0
property real maximumValue: 100
property real currentValue: 33// this is the angle that splits the circle in two arcs// first arc is drawn from 0 radians to angle radians// second arc is angle radians to 2*PI radians
property real angle: (currentValue - minimumValue) / (maximumValue - minimumValue) * 2 * Math.PI
// we want both circle to start / end at 12 o'clock// without this offset we would start / end at 9 o'clock
property real angleOffset: -Math.PI / 2
property string text: "Text"
signal clicked()
onPrimaryColorChanged: requestPaint()
onSecondaryColorChanged: requestPaint()
onMinimumValueChanged: requestPaint()
onMaximumValueChanged: requestPaint()
onCurrentValueChanged: requestPaint()
onPaint: {
var ctx = getContext("2d");
ctx.save();
ctx.clearRect(0, 0, canvas.width, canvas.height);
// fills the mouse area when pressed// the fill color is a lighter version of the// secondary colorif (mouseArea.pressed) {
ctx.beginPath();
ctx.lineWidth = 1;
ctx.fillStyle = Qt.lighter(canvas.secondaryColor, 1.25);
ctx.arc(canvas.centerWidth,
canvas.centerHeight,
canvas.radius,
0,
2*Math.PI);
ctx.fill();
}
// First, thinner arc// From angle to 2*PI
ctx.beginPath();
ctx.lineWidth = 1;
ctx.strokeStyle = primaryColor;
ctx.arc(canvas.centerWidth,
canvas.centerHeight,
canvas.radius,
angleOffset + canvas.angle,
angleOffset + 2*Math.PI);
ctx.stroke();
// Second, thicker arc// From 0 to angle
ctx.beginPath();
ctx.lineWidth = 3;
ctx.strokeStyle = canvas.secondaryColor;
ctx.arc(canvas.centerWidth,
canvas.centerHeight,
canvas.radius,
canvas.angleOffset,
canvas.angleOffset + canvas.angle);
ctx.stroke();
ctx.restore();
}
Text {
anchors.centerIn: parent
text: canvas.text
color: canvas.primaryColor
}
MouseArea {
id: mouseArea
anchors.fill: parent
onClicked: canvas.clicked()
onPressedChanged: canvas.requestPaint()
}
}
Solution 2:
I found a kinda elegant solution in plain QML which can be also used for styling a regular QtQuick ProgressBar component. The idea behind this is to use a ConicalGradient
on a border-only Rectangle
.
Here is the code:
importQtQuick2.3importQtQuick.Controls.Styles1.2importQtGraphicalEffects1.0ProgressBarStyle
{
panel : Rectangle
{
color: "transparent"implicitWidth: 80implicitHeight: implicitWidth
Rectangle
{
id: outerRing
z: 0
anchors.fill: parent
radius: Math.max(width, height) / 2color: "transparent"
border.color: "gray"
order.width: 8
}
Rectangle
{
id: innerRing
z: 1
anchors.fill: parent
anchors.margins: (outerRing.border.width - border.width) / 2
radius: outerRing.radius
color: "transparent"
border.color: "darkgray"
border.width: 4
ConicalGradient
{
source: innerRing
anchors.fill: parent
gradient: Gradient
{
GradientStop { position: 0.00; color: "white" }
GradientStop { position: control.value; color: "white" }
GradientStop { position: control.value + 0.01; color: "transparent" }
GradientStop { position: 1.00; color: "transparent" }
}
}
}
Text
{
id: progressLabel
anchors.centerIn: parent
color: "black"text: (control.value * 100).toFixed() + "%"
}
}
}
Solution 3:
I came across an example by Diego Dotta on GitHub using two rotating circles that seems to work nicely for this use case. It involves setting the duration of a PropertyAnimation. So while this works well for a timer that you can set, it would need a different approach for something you didn't know how long it would take. This is tweaked a bit and ported to QtQuick 2.0:
main.qml:
importQtQuick2.0importUbuntu.Components0.1Rectangle {
width:units.gu(50)height:units.gu(50)property int seconds :0LoadCircle {
id:circleanchors.centerIn:parentloadtimer:10*1000//10secondsComponent.onCompleted:start();onFinishedChanged: {
timer.stop();borderColor="green"
}
}
Rectangle {
id :theTimeranchors.centerIn:parentwidth :units.gu(10);height:units.gu(10)Label {
text:secondsfont.bold:truefontSize:"x-large"anchors.centerIn:parent
}
}
Timer {
id:timerinterval:1000;running:true;repeat:true;onTriggered:seconds++;
}
}
LoadCircle.qml:
importQtQuick2.0importUbuntu.Components0.1Row{id:circleproperty int loadtimer:4000property color circleColor:"transparent"property color borderColor:"red"property int borderWidth:10property alias running:initCircle.runningproperty bool finished:false;width:units.gu(30)height:widthfunctionstart(){part1.rotation=180part2.rotation=180initCircle.start()}functionstop(){initCircle.stop()}Item{width:parent.width/2height:parent.heightclip:trueItem{id:part1width:parent.widthheight:parent.heightclip:truerotation:180transformOrigin:Item.RightRectangle{width:circle.width-(borderWidth*2)height:circle.height-(borderWidth*2)radius:width/2x:borderWidthy:borderWidthcolor:circleColorborder.color:borderColorborder.width:borderWidthsmooth:true}}}Item{width:parent.width/2height:parent.heightclip:trueItem{id:part2width:parent.widthheight:parent.heightclip:truerotation:180transformOrigin:Item.LeftRectangle{width:circle.width-(borderWidth*2)height:circle.height-(borderWidth*2)radius:width/2x:-width/2y:borderWidthcolor:circleColorborder.color:borderColorborder.width:borderWidthsmooth:true}}}SequentialAnimation{id:initCirclePropertyAnimation{target:part2;property:"rotation";to:360;duration:loadtimer/2}PropertyAnimation{target:part1;property:"rotation";to:360;duration:loadtimer/2}ScriptAction { script:finished=true; }
}}
Solution 4:
I know the solution using rotation
property. See example
https://gitorious.org/apps-4-me/staq-me/source/fd20fe5b6fec053f364219842905e2afc5cfdc9d:ui.qml#L172
Solution 5:
Just use EEIoT (https://github.com/IndeemaSoftware/EEIoT) Knob component. Change parameters fromAngle: 0 and toAngle: Math.PI * 2. Also reverse: true if you need progress to be reversed
Knob {
id:knobx:0y:83width:100height:100from:0to:100fromAngle:0toAngle:Math.PI*2reverse:false
}
Post a Comment for "How To Create A Circular Progress Bar In Pure Qml+js?"