SPlatten
SPlatten

Reputation: 5760

QML hack/fiddle to get something to trigger change in state

I'm pretty new to working with QML, we have some buttons that are enabled and disabled according to other content on the page. When the other controls are updated there is some JavaScript functions that can be used to determine if the buttons should be enabled or disabled. Originally these functions were assigned to the qml buttons enabled properties, however it seems this isn't enough and a fiddle to make it work is to have a property defined in QML (integer) which is incremented and this is then used by the enabled property to flag an update, this works but seems very hacky and not the correct way to do it.

    Item {    
        id: root
        property int qmlChangeFiddle: 0
        ...
        Button {
            id: prevImageButton
            anchors.left: parent.left
            anchors.leftMargin: 24
            anchors.top: capturedAreaRect.top
            enabled: (root.qmlChangeFiddle > 0)
            height: cameraButtonBar.height
            width: cameraButtonBar.width * 0.125
            icon: "leftarrow.svg"
            visible: capturedFrame.visible && (imageCaptureModel.capturableSelected.length > 1)
            ....
        }
    }

Incrementing "root.qmllChangeFiddle" will cause it to change and the button enabled, before I was calling a JavaScript routine which returns true or false but this didn't work.

Original qml which doesn't work:

    Item {    
        id: root
        ...
        Button {
            id: prevImageButton
            anchors.left: parent.left
            anchors.leftMargin: 24
            anchors.top: capturedAreaRect.top
            enabled: images.moreThanOne()
            height: cameraButtonBar.height
            width: cameraButtonBar.width * 0.125
            icon: "leftarrow.svg"
            visible: capturedFrame.visible && (imageCaptureModel.capturableSelected.length > 1)
            ....
        }
    }

Upvotes: 0

Views: 99

Answers (2)

Soheil Armin
Soheil Armin

Reputation: 2795

Function return values are not automatically re-evaluated in QML until at least one of the function arguments is updated AND the argument should be a QML object property. I can recommend two approaches:

  • You should bind the prevImageButton to moreThanOne function while the moreThanOne accepts a property of its own object (here image) where that property is being changed when the images object is updated
    Images{
        id:images
        ....
        property var updateCounter : 0

        function whichEverFunctionThatUpdatesImages(){
            ...
            updateCounter++;
        }
        function moreThanOne(uc){
            // you may want to use it or not
            .... return count>0;
        }
    }

    Button{
       enabled : images.moreThanOne(images.updateCounter)
    }

  • Define a property inside Images which is update by moreThanOne and bind it instead
Images{
        id:images
        ....
        property var updateCounter : 0
        property var twoOrMore : false

        function whichEverFunctionThatUpdatesImages(){
            ...
            twoOrMore = iCount > 1 ;
        }
    }

    Button{
       enabled : images.twoOrMore
    }

I choose the latter option.

EDIT:

The following example works quite well on btn2 without using the above methods. But if I use anything other than QML properties like an attribute from a javascript object like what is happening on moreThanOne2() method, then it stops to work out of the box and those two approaches for re-evaluation will work.

 Item {
        id : item
        anchors.fill: parent

        property var aCounter: 0
        property var someObject: ({ counter: 0})

        Button{
            anchors.top: parent.top
            text: 'btn1'
            onClicked: {
                parent.aCounter++
                parent.someObject.counter++
            }
        }

        Button{
            anchors.bottom: parent.bottom
            anchors.left: parent.left
            text: 'btn2'
            enabled: item.moreThanOne1()
        }

        Button{
            anchors.bottom: parent.bottom
            anchors.right: parent.right
            text: 'btn3'
            enabled: item.moreThanOne2()
        }


        function moreThanOne1(){
            return aCounter > 1;
        }

        function moreThanOne2(){
            return someObject.counter > 1;
        }
    }

Upvotes: 2

SPlatten
SPlatten

Reputation: 5760

The actual solution which works is to use Qt.binding:

        Item {    
            id: root
            ...
            Button {
                id: prevImageButton
                anchors.left: parent.left
                anchors.leftMargin: 24
                anchors.top: capturedAreaRect.top
                enabled: Qt.binding(images.moreThanOne())
                height: cameraButtonBar.height
                width: cameraButtonBar.width * 0.125
                icon: "leftarrow.svg"
                visible: capturedFrame.visible && (imageCaptureModel.capturableSelected.length > 1)
                ....
            }
        }

Upvotes: 0

Related Questions