Unable to assign [undefined] to double

Viewed 61

I am Learning QML newly and am trying to resolve the following warning: [warning] main.qml:392:25: Unable to assign [undefined] to double

main.qml

Rectangle{
    id: rect
    ...
    readonly property real scale0: (rotateRepeater.yPointM - rotateRepeater.yPointT) / height
    readonly property real scale1: (rotateRepeater.yPointB - rotateRepeater.yPointM) / height
    readonly property real yScale: [scale0, scale1][index] // Warning is in this line
}

The error is being show for property yScale.

Method 1 that I tried was -

readonly property real yScale: Binding {
                        when: onScale0Changed && onScale1Changed
                        yScale: [scale0, scale1][index]
                    }

and got the following error : "cannot assign to non-existent property "yScale"

I tried Googling and found out two possible answers -https://stackoverflow.com/questions/52290153/qml-unable-to-assign-undefined-to -https://stackoverflow.com/questions/73306793/qml-failure-accessing-properties-with-error-unable-to-assign-undefined-to

but, I was unable to solve the warning. Any help here is much appreciated.

Thanks in Advance.

3 Answers

As I said above, you probably set incorrect index that is out of range. Check this code:

Item {
    id: item
    property int index: 0
    property double value: [1.0, 2.0, 3.0][index]
    onValueChanged: {
        console.log(value)
    }

    Timer {
        interval: 1000;
        running: true;
        repeat: true
        onTriggered: item.index = Math.round(Math.random() * 3)
    }
}

The output is possible will be:

qml: 1
qml: 3
qml: 2
main.qml:18:9: Unable to assign [undefined] to double
qml: 3
qml: 2
qml: 3
main.qml:18:9: Unable to assign [undefined] to double 

Do this:

Rectangle{
    id: rect
    ...
    readonly property real scales: [(rotateRepeater.yPointM - rotateRepeater.yPointT) / height ,
    (rotateRepeater.yPointB - rotateRepeater.yPointM) / height]
    readonly property real yScale: scales[index] // Warning is in this line
}

Property evaluations are arbitrarily ordered, so the eval of yScale may happen when either scale0 or scale1 are not evaluated yet. There is also a possibility that the index value is out of range, as mentioned in other answers.

Quote from the Qt documentation:

Syntactically, bindings are allowed to be of arbitrary complexity. However, if a binding is overly complex - such as involving multiple lines, or imperative loops - it could indicate that the binding is being used for more than describing property relationships. Complex bindings can reduce code performance, readability, and maintainability. It may be a good idea to redesign components that have complex bindings, or at least factor the binding out into a separate function. As a general rule, users should not rely on the evaluation order of bindings.

Some further explorative testing is required for you to narrow down the cause of the undefined values. Here's one way how you can achieve further debugging:

Rectangle{
    id: rect
    ...
    readonly property real scale0: (rotateRepeater.yPointM - rotateRepeater.yPointT) / height
    readonly property real scale1: (rotateRepeater.yPointB - rotateRepeater.yPointM) / height
    readonly property real yScale: getYScale(scale0, scale1, index)
    function getYScale(scale0, scale1, index) {
        console.log("scale0: ", scale0, "scale1: ", scale1, "index: ", index);
        return [scale0, scale1][index];
    }
}

I made an assumption that I believe one of your inputs has an undefined value, and that undefined value was, possibly momentary. Doing the above code will not only help you see which parameter it is but, that function may get triggered multiple times so you can see it transition from an undefined state to a defined state. Then, you can build error handling in your function, e.g.

    function getYScale(scale0, scale1, index) {
        console.log("scale0: ", scale0, "scale1: ", scale1, "index: ", index);
        if (scale0 === undefined) scale0 = 0;
        if (scale1 === undefined) scale1 = 0;
        if (index === undefined) index = 0;
        let result = [scale0, scale1][index];
        if (result === undefined) result = 0;
        return result;
    }

Doing the above actually has a lot of paranoid edge case handling, but, it should give you a deeper understanding of the intermediate values used in your property binding and help tailor a fix. Once you get the problem solved, you can discard the above function and incorporate the result back into a 1 line solution, perhaps something like:

Rectangle{
    id: rect
    ...
    readonly property real scale0: (rotateRepeater.yPointM - rotateRepeater.yPointT) / height
    readonly property real scale1: (rotateRepeater.yPointB - rotateRepeater.yPointM) / height
    readonly property real yScale: [scale0 ?? 0, scale1 ?? 0][index ?? 0] ?? 0
}
Related