False binding loop?



  • Hi,

    since Qt 5.10.1 I'm getting this warning: Binding loop detected for property "textLengthType"

    I post here rather the whole code. It's quite long but I'll try to explain shortly what I'm doing here. I have a menu at bottom of my app and I want to show only an icon, a short text or a long text, depending on the space available. The variable textLengthType holds which of these 3 text types should be displayed.

    I don't think there is anything wrong in my code. Is this is a false positive warning or is there a mistake?

    import QtQuick 2.6
    
    Row {
        property int buttonWidth: textLengthType == 1 ? maxTextSize+units.gu(4) : textLengthType == 2 ? maxTextSizeShort+units.gu(4) : main.width/(itemsCount+1)
        property int distance: (main.width-itemsCount*buttonWidth)/(itemsCount+1)
        property int active: -1
        property int itemsCount: 4
        property int maxTextSize: Math.max(text1.width, text2.width, text3.width, text4.width)
        property int maxTextSizeShort: Math.max(text1.width, text5.width, text6.width, text7.width)
        property int textLengthType: (maxTextSize+units.gu(5))*itemsCount < main.width ? 1 : (maxTextSizeShort+units.gu(5))*itemsCount < main.width ? 2 : 3
        anchors.leftMargin: distance
        anchors.rightMargin: distance
        spacing: distance
    
        function showActive() {
            active = 0;
        }
    
        function hideActive() {
            active = -1;
        }
    
    
        Rectangle {
            width: buttonWidth
            height: parent.height-units.gu(2)
            color: "#00000000"
            border.width: units.dp(2)
            border.color: active == 0 ? main.selectionColor : "#00000000"
            radius: buttonWidth/8
    
            ToolbarButton {
                width: buttonWidth
                height: parent.height
                iconSource:"images/check.svg"
                text: textLengthType == 3 ? "" : qsTr("Apply")
                onTriggered: {
                    settingsTab.apply()
                }
            }
        }
    
        Rectangle {
            width: buttonWidth
            height: parent.height-units.gu(2)
            color: "#00000000"
            border.width: units.dp(2)
            border.color: active == 1 ? main.selectionColor : "#00000000"
            radius: buttonWidth/8
    
            ToolbarButton {
                width: buttonWidth
                height: parent.height
                iconSource:"images/cancel.svg"
                text: textLengthType == 1 ? qsTr("Cancel Changes") : textLengthType == 2 ? qsTr("Cancel") : ""
                onTriggered: {
                    settingsTab.cancel()
                }
            }
        }
    
        Rectangle {
            width: buttonWidth
            height: parent.height-units.gu(2)
            color: "#00000000"
            border.width: units.dp(2)
            border.color: active == 2 ? main.selectionColor : "#00000000"
            radius: buttonWidth/8
    
            ToolbarButton {
                width: buttonWidth
                height: parent.height
                iconSource:"images/import.svg"
                text: textLengthType == 1 ? qsTr("Import Settings") : textLengthType == 2 ? qsTr("Import") : ""
                onTriggered: {
                    settingsTab.importSettings()
                }
            }
        }
    
        Rectangle {
            width: buttonWidth
            height: parent.height-units.gu(2)
            color: "#00000000"
            border.width: units.dp(2)
            border.color: active == 3 ? main.selectionColor : "#00000000"
            radius: buttonWidth/8
    
            ToolbarButton {
                width: buttonWidth
                height: parent.height
                iconSource:"images/export.svg"
                text: textLengthType == 1 ? qsTr("Export Settings") : textLengthType == 2 ? qsTr("Export") : ""
                onTriggered: {
                    settingsTab.exportSettings()
                }
            }
        }
        TextMetrics {
            id: text1
            font.pixelSize: config.verySmallFontSize
            text: qsTr("Apply")
        }
    
        TextMetrics {
            id: text2
            font.pixelSize: config.verySmallFontSize
            text: qsTr("Cancel Changes")
        }
    
        TextMetrics {
            id: text3
            font.pixelSize: config.verySmallFontSize
            text: qsTr("Import Settings")
        }
    
        TextMetrics {
            id: text4
            font.pixelSize: config.verySmallFontSize
            text: qsTr("Export Settings")
        }
    
        TextMetrics {
            id: text5
            font.pixelSize: config.verySmallFontSize
            text: qsTr("Cancel")
        }
    
        TextMetrics {
            id: text6
            font.pixelSize: config.verySmallFontSize
            text: qsTr("Import")
        }
    
        TextMetrics {
            id: text7
            font.pixelSize: config.verySmallFontSize
            text: qsTr("Export")
        }
    }
    
    


  • Nobody has an idea? So I'll try to make a stripped down version and report it as a bug.



  • @vlada hi,
    usually I would say, no, not a false positive.

    try to replace the ToolbarButton geometry with something differen

    //from 
    ToolbarButton {
                width: buttonWidth
                height: parent.height
                iconSource:"images/export.svg"
                ....
    }
    //to
    ToolbarButton {
                anchors.fill: parent
                iconSource:"images/export.svg"
                ....
    }
    

    see if that helps.



  • That indeed fixes the problem but then it won't work as expected. So it is not a solution.

    I just found out that it only happens on Android. If I compile the same application with the same Qt 5.10.1 but on desktop (Windows) I don't get the warning. I think this makes it more obvious that the problem is probably not in my code.



  • @vlada said in False binding loop?:

    That indeed fixes the problem but then it won't work as expected. So it is not a solution.

    how does it behave differently?
    You don't specify a x or y in your toolbutton so it defaults to 0

    and

    ToolbarButton {
         x: 0
         y:0
         width: buttonWidth //parent.width == buttonWidth in your case
         height: parent.height
    }
    

    should be the same as

    ToolbarButton {
        anchors.fill: parent  
    }
    

    I just found out that it only happens on Android. If I compile the same application with the same Qt 5.10.1 but on desktop (Windows) I don't get the warning. I think this makes it more obvious that the problem is probably not in my code.

    That is indeed strange!



  • The ToolbarButton is a component for bottom menu with buttons and text, it was introduced in Ubuntu Touch and I made my own implementation for other OSs.

    The 5 buttons are in a Row component, which sets the x property. Of course I could have set the ToolbarButton to anchors.fill: parent. I suppose I did it this way because of Ubuntu Touch (which is now obsolete) compatibility. But changing it only here won't bring anything. I would have to replace the buttonWidth property completely.

    Anyway the problem is in the textLengthType property, not the buttonWidth. I made a test application with exactly this code and I can not reproduce it! Very weird and annoying issue.

    There are no problems regarding function, everything works as intended. I just get these warnings in console. To see how it looks like, have a look at this screenshot. The component in my code is the bottom menu.

    I found a workaround to the issue. You can see that I calculate the maximum text size for the short and long variants. It is stored to variables maxTextSize and maxTextSizeShort. Some of the TextMetrics items are used in both because there is only one text variant for both cases. But if I duplicate them so that each item is used only once, I don't get this warning anymore. Do you see there any logic? I don't. :-(



  • @vlada said in False binding loop?:

    There are no problems regarding function, everything works as intended. I just get these warnings in console. To see how it looks like, have a look at this screenshot. The component in my code is the bottom menu.

    Well they are not warnings, they are actuall errors. It detected, that the property changes its value again, weil it's still updating all bound properties and values during the eventloop cycle and - to prevent a deadlock - breaks the loop by stopping the property calculation/update.
    This could stop in an state, that represents your expected result, but it might just as well not. That's more or less random. Firstupdate always wins

    I found a workaround to the issue. You can see that I calculate the maximum text size for the short and long variants. It is stored to variables maxTextSize and maxTextSizeShort. Some of the TextMetrics items are used in both because there is only one text variant for both cases. But if I duplicate them so that each item is used only once, I don't get this warning anymore. Do you see there any logic? I don't. :-(

    I think I do, when a property calculates the initial value or gets chaged, all properties influenzed or bound to that property update as well

    //assume
    property bool c : a < b
    property int i : c*100
    

    c gets updated when a changes and updates again wenn b changes, and therefore i gets updated when a changes and again when b changes.

    What I'm trying to say,
    the most common error you'll have with QML are binding loops and in 99.99 % of all cases those are not false detections or qml errors, but the human coder created made them. Usually by accident.



  • Instead of a Row, try using an RowLayout.
    Set the minimum and maximum width of the ToolbarButtons and ensure to set the property fillWidth as true.



  • @J-Hilk Yes, I understand that and if it would be just a useless warning I wouldn't care about that. I know it is an actual error. But I just don't see it. And furthermore I didn't get the error before Qt 5.10, it only happens on Android and disappears after a change in code which don't change the actual functionality at all. All this makes me believe the fault is not in my code.

    This is how the affected property is calculated:

    1. Calculate TextMetrics for all the texts
    2. Get the longest one (for both short and long variants)
    3. Compare if the the texts are not too long to fit in current width and decide which type to show (no text, short text, long text)

    I don't see a binding loop in this calculation.

    @Maheshdev305 Thanks for the hint. I'll try that if it makes any change. Basically I know how to fix it and avid the error. It just doesn't make much sense.



  • I think I finally found the reason why I'm getting the error. I changed too many things at once and did a wrong conclusion.

    So the real problem is that the TextMetrics objects are inside the row and are probably affected by it. I think they shouldn't, but it just happens. The solution is to remove them from the row.

    Why this only happens on Android and since Qt 5.10, I have no idea. But at least I have a solution.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.