Important: Please read the Qt Code of Conduct -

Rounded button with progress background fill

  • Hi,

    I would like to create a count-down button with rounded corners and a background that fills/empties proportionally to the elapsed time. Something like this:0_1516664109975_CountDownButton.png

    I thought I could do this using two rectangles as the button background where the black one has a width proportional to the time and the corners on the left would be clipped by the other Rectangle. Something like this:

    	id: control
    	background: Rectangle {
    		id: backgroundRect
    		implicitWidth: 100
    		implicitHeight: 60
    		radius: height / 2
    		anchors.fill: parent
    		color: "gray"
    			id: progressRect
    			anchors.verticalCenter: backgroundRect.verticalCenter
    			anchors.left: backgroundRect.left
    			clip: true
    			height: backgroundRect.height
    			width: relativeCounter*backgroundRect.width
    			color: "black"

    However the clipping works only along the bounding box, i.e. the corners on the left are not rounded:

    I tried OpacityMask in the GraphicalEffects module, but I think I cannot use the parent rectangle as mask. I tried to work around it but could not get it to run. The last option I see is using Canvas and describing the round corners mathematically.

    I am new to QML so it is quite possible that I did something wrong in the steps I tried or that I am missing a simpler option.

    If anyone has an idea how it should work or can confirm that something does not work, I am grateful for any help.

    Thanks in advance

  • Moderators

    @markugra said in Rounded button with progress background fill:

    I tried OpacityMask in the GraphicalEffects module, but I think I cannot use the parent rectangle as mask.

    exactly, you need to place the button and the rectangle "beside the button on the same level"
    You could group the button and the rectangle into a custom component then.
    See the example in the docs and replace it analogous with your button and rectangle elements.

  • Thanks, I tried the OpacityMask again as you suggested and it works now. It took me a bit to get it right, because i) I had a warning about the recursive property in ShaderEffectSource needing to be set to "true" and ii) the mask size needs to be the same as the source size for it to work properly. After a while I noticed that i) originated from some code in the contentItem of the button using the ColorOverlay (in fact it was the same problem there i.e. I tried to apply it to the parent). To fix ii) I used a transparent frame so that the code now looks something like:

                width: control.width
                height: control.height
                    id: progressFrame
                    anchors.fill: parent
                    color: "transparent"
                    visible: false
                        id: progressRect
                        width: 0.7*parent.width
                        height: parent.height
                        anchors.verticalCenter: parent.verticalCenter
                        anchors.left: parent.left
                        color: "green"
                Rectangle {
                    id: backgroundRect
                    anchors.fill: parent
                    radius: height / 2
                    color: "red"
                    visible: true
                anchors.fill: progressFrame
                source: progressFrame
                maskSource: backgroundRect

    Resulting in:

    Thanks again!