Home > Mobile >  Changing color and Showing count down timer on button created by Repeater model qml
Changing color and Showing count down timer on button created by Repeater model qml

Time:09-01

I am learning qml and i am trying to make an sample application that achieves the below use case.

Use Case : When user presses on button in qml scene

  1. Icon on button has to be updated.
  2. Color of the button has to updated (i am trying to use foreground from qml but unable to acheive).
  3. Count down timer has to be displayed on top of button.

Ex : Let's say when the Cam button is clicked, i wanted to update the icon from small circle to elliptical curve, change the color of Cam button and after color is applied i wanted to display a count down timer with some n value.

All the specified above expectation has to be applied only for Cam button that was rendered through Repeater model.

Attaching the code i tried

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window{
    width: 640
    height: 480
    visible: true
    color: "pink"
    title: qsTr("Repeater Button Panel")
    Body{
    }
    Test{
    }
}

Body.qml

import QtQuick 2.0
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

Item {
    id:root
    width: 640
    height: 480
    
    property color bgColor

    signal repeaterbuttonpressed(int index,string buttonname)
    
Rectangle{
        width: 250
        height: 600
        color: "beige"
        border.color: "black"
    }
    
ListModel{
        id:listModel
        ListElement{
            name:"G"
        }
        ListElement{
            name:"M"
        }
        ListElement{
            name:"Mu"
        }
        ListElement{
            name:"Cam"
        }
        ListElement{
            name:"Im"
        }
        ListElement{
            name:"Ph"
        }
    }
    Flickable{
        x:scrollBar.x
        y:250
        anchors.fill: parent
        contentHeight: 2000
        Grid{
            id:scrollBar
            rows:8
            columns: 2
            spacing: 10
            Repeater{
                model:listModel
                Button{
                    id:btn
                    text:name
                    onClicked: {
                        repeaterbuttonpressed(index,name)
                    }
                }
            }
        }
        ScrollBar.vertical:ScrollBar{
            id:vbar; active: true
        }
}
}

Test.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Item {
    Body{
        id:bodyId

        onRepeaterbuttonpressed: {
            //Here i wanted to implement logic to update icon, color, display count down timer for Cam button
            console.log("inside the on repeater button pressed",index,buttonname)
        }

        function myRepeaterbuttonpressed(index,buttonname)
        {
            console.log("myrepeaterbutton " buttonname)
            console.log("myrepeaterbutton " index)
        }
        Component.onCompleted: {
            repeaterbuttonpressed.connect(myRepeaterbuttonpressed)
        }
    }
}

Attaching button expectation image for better understanding, any suggestions on how to achieve the same would be much appreciated.

enter image description here

enter image description here

import QtQuick
import QtQuick.Controls

ApplicationWindow {
    id: root
    visible: true
    width: 640
    height: 480
    title: "Button with Timer"

    ListModel {
        id: fruitModel

        ListElement {
            name: "Apple"
            colorValue: "crimson"
        }
        ListElement {
            name: "Kiwi"
            colorValue: "sienna"
        }
        ListElement {
            name: "Banana"
            colorValue: "gold"
        }
    }


    Row {
        spacing: 10
        anchors.centerIn: parent

        Repeater {
            model: fruitModel
            delegate: SpecialButton {
                id: delegateRoot

                required property string name
                required property color colorValue

                text: delegateRoot.name
                backgroundColor: delegateRoot.colorValue
            }
        }
    }

    component SpecialButton: Button {
        id: control

        property color backgroundColor: "royalblue"

        text: qsTr("Button")

        Timer {
            id: timer

            property int count: 5

            interval: 1000
            running: false
            repeat: true
            onTriggered: {
                --timer.count

                if (timer.count === -1) {
                    timer.stop()
                    timer.count = 5
                }
            }
        }

        contentItem: Item {
            anchors.fill: parent

            Column {
                anchors.centerIn: parent

                Item {
                    width: 40
                    height: 40

                    Rectangle {
                        id: circle

                        property int xScale: timer.running ? 2 : 1

                        radius: circle.height
                        color: "royalblue"
                        border.color: "navy"
                        border.width: 1
                        anchors.fill: parent
                        anchors.horizontalCenter: parent.horizontalCenter

                        transform: Scale {
                            origin.x: circle.width / 2
                            origin.y: circle.height / 2
                            xScale: circle.xScale
                        }
                    }

                    Text {
                        anchors.centerIn: parent
                        text: timer.count
                        visible: timer.running
                        color: "white"
                    }
                }

                Text {
                    text: control.text
                    font: control.font
                    color: timer.running ? "black" : "white"
                    horizontalAlignment: Text.AlignHCenter
                    verticalAlignment: Text.AlignVCenter
                    elide: Text.ElideRight
                    anchors.horizontalCenter: parent.horizontalCenter
                }
            }
        }

        background: Rectangle {
            implicitWidth: 100
            implicitHeight: 100
            border.color: "navy"
            border.width: 1
            color: timer.running ? "darkorange" : control.backgroundColor
        }

        onClicked: timer.start()
    }
}

CodePudding user response:

A suggested minimal changes to your code that approximate your criteria:

  1. added the delegate keyword to the Repeater - hard to explain, but it feels right to do so
  2. introduce an inactive Timer property inside your Button
  3. use property binding so that Timer automatically starts when countdown === 5 and automatically stops when countdown === 0
  4. use the background property of your Button to configure a custom layout
  5. I use the Frame component to magically wrap my countdown Text component without specifying numbers for margins or padding
  6. approximate an ellipse simply by using Frames with a background Rectangle appearance with rounded corners (see radius: height / 2)
  7. I also increased the size of your buttons with width: 100 and height: 100 so that the background is rendered nicely
            Repeater{
                model:listModel
                delegate: Button {
                    id: btn
                    width: 100
                    height: 100
                    property int countdown: 0
                    property Timer countdownTimer: Timer {
                        interval: 1000
                        running: countdown > 0
                        repeat: true
                        onTriggered: countdown--;
                    }
                    text: name
                    background: Rectangle {
                        color: countdownTimer.running ? "orange" : "royalblue"
                        Frame {
                            anchors.horizontalCenter: parent.horizontalCenter
                            anchors.top: parent.top
                            visible: countdownTimer.running
                            background: Rectangle {
                                border.color: "black"
                                color: "royalblue"
                                radius: height / 2
                            }
                            Text {
                                text: countdown
                            }
                        }
                    }
                    onClicked: {
                        countdown = 5;
                        repeaterbuttonpressed(index,name)
                    }
                }

You can use the Rectangle component to render either an ellipse or a circle. For a perfect circle, you set width === height. For an ellipse you can set width > height assuming that your ellipse grows horizontally, you can set radius: height / 2. If the ellipse can stretch in either direction, you can generalize with radius: Math.min(width, height) / 2.

Rectangle {
    width: 50
    height: 50
    radius: height / 2
}
  • Related