QML Binding loop detected for property, what is the cause?
-
I'm working on a project and trying to improve the error handling, this is driving me crazy. No matter what I try I'm still getting 3 QML messages on start-up that I just don't understand the cause of:
qrc://qml/Modes/ModePreview.qml:185:17: QML ModeSelection: Binding loop detected for property "selectedItemIndex"
In the original code I thought the cause of this was a reference to an object that was not ready so I added a JavaScript function to test the object exhaustively before trying to access the property. This is the part of the QML that is causing the issues:
StackLayout { id: stackLayout anchors.top: tabBar.bottom anchors.left: tabBar.left anchors.right: tabBar.right anchors.bottom: cameraSelector.top currentIndex: tabBar.currentIndex readonly property int tabIndexLocal: 0 readonly property int tabIndexMachine: 1 readonly property int tabIndexTemplates: 2 property var currentItem: children[currentIndex] property var lastSelected: ["","",""] function handleSelectedPathChanged(path) { if ( typeof path == "object" && typeof path.length == "number" && path.length > 0) { workingModeSelected = false } } function getItem(member) { if ( typeof stackLayout.currentItem == "object" && typeof stackLayout.currentItem[member] != "undefined" ) { return stackLayout.currentItem[member]; } return -1; } function pathChanged(index, selectedPath) { var rc = false; if ( index >= stackLayout.tabIndexLocal && index <= stackLayout.tabIndexTemplates ) { if ( typeof selectedPath == "object" && typeof selectedPath.length == "number" && selectedPath.length > 0 ) { if ( typeof stackLayout.lastSelected[index] === "string" && stackLayout.lastSelected[index] !== selectedPath[0] ) { stackLayout.lastSelected[index] = selectedPath[0]; rc = true; } } } return rc; } ModeSelection { id: localModesList modeType: ModePreviewManager.LocalModeType modePreviewModel: modePreviewManager.localModes onModePreviewModelChanged: selectedPath = [] onSelectedPathChanged: { stackLayout.handleSelectedPathChanged(selectedPath); if ( stackLayout.pathChanged(stackLayout.tabIndexLocal, selectedPath) === true ) { modeSelectionArea.refreshHighlight(); } } } ModeSelection { id: machineModesList modeType: ModePreviewManager.MachineModeType modePreviewModel: modePreviewManager.machineModes onModePreviewModelChanged: selectedPath = [] onSelectedPathChanged: { stackLayout.handleSelectedPathChanged(selectedPath) if ( stackLayout.pathChanged(stackLayout.tabIndexMachine, selectedPath) === true ) { modeSelectionArea.refreshHighlight(); } } onItemCountChanged: { if ( machineModesList.itemCount > 0 ) { tabBar.currentIndex = stackLayout.tabIndexMachine machineModesList.setSelected(machineModesList.itemCount - 1); ModeDetails.stopBusyAnim(); } } } ModeSelection { id: templateModeList modeType: ModePreviewManager.TemplateModeType modePreviewModel: modePreviewManager.templateModes onModePreviewModelChanged: selectedPath = [] onSelectedPathChanged: { stackLayout.handleSelectedPathChanged(selectedPath) if ( stackLayout.pathChanged(stackLayout.tabIndexTemplates, selectedPath) === true ) { modeSelectionArea.refreshHighlight(); } } } }
What is causing the loop?
-
It doesn't really make much sense, line 185 is the line starting "ModeSelection {", this is the first "ModeSelection {" with "id: localModesList" which is also the tab I am currently viewing.
-
I'm quite new to QML, is there any error handling I can introduce that would help me trace this?
In the file ModeSelection.qml, near the top along with some other properties:
property int selectedItemIndex: { //Some logic to get the index, if it fails return -1 }
-
I'm working on a project and trying to improve the error handling, this is driving me crazy. No matter what I try I'm still getting 3 QML messages on start-up that I just don't understand the cause of:
qrc://qml/Modes/ModePreview.qml:185:17: QML ModeSelection: Binding loop detected for property "selectedItemIndex"
In the original code I thought the cause of this was a reference to an object that was not ready so I added a JavaScript function to test the object exhaustively before trying to access the property. This is the part of the QML that is causing the issues:
StackLayout { id: stackLayout anchors.top: tabBar.bottom anchors.left: tabBar.left anchors.right: tabBar.right anchors.bottom: cameraSelector.top currentIndex: tabBar.currentIndex readonly property int tabIndexLocal: 0 readonly property int tabIndexMachine: 1 readonly property int tabIndexTemplates: 2 property var currentItem: children[currentIndex] property var lastSelected: ["","",""] function handleSelectedPathChanged(path) { if ( typeof path == "object" && typeof path.length == "number" && path.length > 0) { workingModeSelected = false } } function getItem(member) { if ( typeof stackLayout.currentItem == "object" && typeof stackLayout.currentItem[member] != "undefined" ) { return stackLayout.currentItem[member]; } return -1; } function pathChanged(index, selectedPath) { var rc = false; if ( index >= stackLayout.tabIndexLocal && index <= stackLayout.tabIndexTemplates ) { if ( typeof selectedPath == "object" && typeof selectedPath.length == "number" && selectedPath.length > 0 ) { if ( typeof stackLayout.lastSelected[index] === "string" && stackLayout.lastSelected[index] !== selectedPath[0] ) { stackLayout.lastSelected[index] = selectedPath[0]; rc = true; } } } return rc; } ModeSelection { id: localModesList modeType: ModePreviewManager.LocalModeType modePreviewModel: modePreviewManager.localModes onModePreviewModelChanged: selectedPath = [] onSelectedPathChanged: { stackLayout.handleSelectedPathChanged(selectedPath); if ( stackLayout.pathChanged(stackLayout.tabIndexLocal, selectedPath) === true ) { modeSelectionArea.refreshHighlight(); } } } ModeSelection { id: machineModesList modeType: ModePreviewManager.MachineModeType modePreviewModel: modePreviewManager.machineModes onModePreviewModelChanged: selectedPath = [] onSelectedPathChanged: { stackLayout.handleSelectedPathChanged(selectedPath) if ( stackLayout.pathChanged(stackLayout.tabIndexMachine, selectedPath) === true ) { modeSelectionArea.refreshHighlight(); } } onItemCountChanged: { if ( machineModesList.itemCount > 0 ) { tabBar.currentIndex = stackLayout.tabIndexMachine machineModesList.setSelected(machineModesList.itemCount - 1); ModeDetails.stopBusyAnim(); } } } ModeSelection { id: templateModeList modeType: ModePreviewManager.TemplateModeType modePreviewModel: modePreviewManager.templateModes onModePreviewModelChanged: selectedPath = [] onSelectedPathChanged: { stackLayout.handleSelectedPathChanged(selectedPath) if ( stackLayout.pathChanged(stackLayout.tabIndexTemplates, selectedPath) === true ) { modeSelectionArea.refreshHighlight(); } } } }
What is causing the loop?
@SPlatten said in QML Binding loop detected for property, what is the cause?:
I'm working on a project and trying to improve the error handling, this is driving me crazy. No matter what I try I'm still getting 3 QML messages on start-up that I just don't understand the cause of:
qrc://qml/Modes/ModePreview.qml:185:17: QML ModeSelection: Binding loop detected for property "selectedItemIndex"
What is causing the loop?
My comment is just a sidenote. Please forgive the intrusion. It comes from empathy and I will be brief.
I've struggled with these, too. The thought that crosses my mind is that something in the codebase (in "qtdeclarative/src" or similar) must be traversing the bits that are circularly linked, so why not print out the cycle along with the "binding loop detected"? I've seen several build tools and compilers do exactly that (print the whole cycle) when they detect cyclic dependencies. One of these days I hope to have time to propose such an enhancement and draft a patch.