Home > Enterprise >  Create conditional button background color in onClicked - QT(qml)
Create conditional button background color in onClicked - QT(qml)

Time:10-29

My goal is that when the button is clicked, the button color changes to orange and stays orange until the result of the if condition is declared. Then I want the button color to be green if the condition is met and red if not. However, when I click the button, the button color does not change until the condition result is clear, and when the condition is certain, the button color becomes either green or red. So the button color never turns orange.

I have shown my button usage below;

Button 
{
    ...
    ...

    onClicked: {
        background.color = "orange"

        if(some_condition))
            background.color = "green"
        else
            background.color = "red"
    }
}

NOTE: I am sending data to a device in an if condition and waiting for its response(this takes about 1-2 seconds). I expect the button to be orange until the answer comes, green if my condition is true after the answer, and red if it is false. But the color of the button does not turn orange.

Do you have any suggestions?

CodePudding user response:

To achieve this, property bindings must be used.

In this example, I'll use Image to demonstrate your loading thing.
For this example, I am providing two methods.

Method one

Thus, the plan is as follows.

  1. I press the Button.
  2. The image's source changes, and it goes to the loading state.
    And the Button turns orange as well.
  3. The Button then turns green if Image enters the ready state.
  4. Or else, the Button turns red.
Grid {
    columns: 1

    Image {
        id: img
        width: 200; height: 200
        fillMode: Image.PreserveAspectFit
    }

    Button {
        palette.button: img.status == Image.Loading ? "orange" :
                        img.status == Image.Ready ? "green" :
                        img.status == Image.Error ? "red" : "#259bd7"

        onClicked: img.source = "https://thispersondoesnotexist.com/image";
    }
}

Method two

Similar to method one in most ways, but not declaratively.
I press the Button, and the Button turns green or red anytime the image status changes.

Grid {
    columns: 1

    Image {
        id: img
        width: 200; height: 200
        fillMode: Image.PreserveAspectFit
        
        onStatusChanged: {
            if(status == Image.Ready) btn.palette.button = "green";
            else if(img.status == Image.Error) btn.palette.button = "red";
        }
    }

    Button {
        id: btn
        palette.button: "#259bd7"
        onClicked: {
            palette.button = "orange"
            img.source = "https://thispersondoesnotexist.com/image";
        }
    }
}

Now, if for some weird reason, you want to do everything in the button, you can put a boolean property and change the color as it changes.
Like:

Image {
    ...
    onStatusChanged: {
        // some code and calculation
        btn.condition = // true or false
    }
}

Button {
    ...
    property bool condition
    onConditionChanged: {
        if(condition) palette.button = "green";
        else palette.button = "red";
    }
    ...
}

Example.qml

Okay, so we now know what the answer is, well let's improve it (In the case that a lazy programmer wants to copy :D).

Image.status is an Enum with values ranging from 0 to 3.

Image {
    id: img
    width: 200; height: 200
    fillMode: Image.PreserveAspectFit
}

Button {
    id: btn
    implicitHeight: 30

    property list<Item> content: [
        Item {},
        Text { text: " ✓" },
        BusyIndicator { running: true },
        Text { text: " ✖" }
    ]

    contentItem: Item {
        width: parent.implicitWidth
        Grid {
            x: (parent.width - width)/2
            spacing: 6
            Text { text: "button" }
            Control { contentItem: btn.content[img.status] }
            Behavior on x { SmoothedAnimation {}}
        }
    }

    onClicked: img.source = "https://thispersondoesnotexist.com/image";
}

Preview

BusyIndicator

CodePudding user response:

In this answer, I manipulate Button background by setting it to a Rectangle and I control the Rectangle's color to iterate between (1) default button color, (2) orange, (3) red and (4) green. Hence, I identified there are 4 unique states as detailed as follows:

  • button hasn't been clicked yet, the button background color is the default color
  • button has been clicked, but the user hasn't typed anything, the button background changes to an "orange" color
  • the text has been entered, but the answer is wrong, the button color changes to "red" color
  • the text has been entered, and the answer is correct. the button background changes to "green" color
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
    property bool started: false

    ColumnLayout {
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.top: parent.top
        anchors.margins: 10

        Label {
            visible: started
            text: qsTr("What is 1 1?")
        }

        Frame {
            Layout.fillWidth: true
            visible: started

            TextEdit {
                id: answer
                width: parent.width
            }
        }
            

        Button {
            background: Rectangle {
                color: started
                   ? answer.text 
                     ? answer.text === "2"
                       ? "green"
                       : "red"
                     : "orange"
                   : palette.button
            }

            text: qsTr("Start")

            onClicked: {
                if (!started) {
                     started = true;
                     answer.text = "";
                } else {
                     started = false;
                }
            }
        }
    }
}

You can Try it Online!

  • Related