Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Strange behavior with dynamically removed objects



  • Hello. I'm noted one situation:

    OwnLabel.qml

    import QtQuick 2.12
    import QtQuick.Controls 2.12
    Label { text: "Own Label" }
    

    main.qml:

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.12
    import QtQuick.Layouts 1.12
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        property var __ownLabelComponent: Qt.createComponent("OwnLabel.qml")
    
        ColumnLayout {
    
            RowLayout {
                Button {
                    text: qsTr("Add")
                    onClicked: {
                        var ownLabel = __ownLabelComponent.createObject(labelsContainter);
                        ownLabel.text += labelsContainter.children.length;
                    }
                }
    
                Button {
                    text: qsTr("Remove")
                    onClicked: {
                        if (labelsContainter.children.length > 0)
                            labelsContainter.children[0].destroy();
    
                        console.log(labelsContainter.children.length);
                    }
                }
    
                Button {
                    text: qsTr("Clear & Add New 3")
                    onClicked: {
                        for (var i = 0; i < labelsContainter.children.length; ++i)
                            labelsContainter.children[i].destroy();
    
                        for (var j = 0; j < 3; ++j) {
                            var ownLabel = __ownLabelComponent.createObject(labelsContainter);
                            ownLabel.text += labelsContainter.children.length;
                        }
    
                        console.log(labelsContainter.children.length);
                    }
                }
            }
    
            ColumnLayout {
                id: labelsContainter
            }
    
        }
    }
    

    If you try to click Add, then Remove and then Add, again, it will work correctly:

    • output "3,2,1,0"
    • 3 elements will be displayed with titles "Own Label 1", "Own Label 2", "Own Label 3"

    But, if you try to click "Clean & Add 3" instead of "Clean", you will see:

    • output, that container have 6 child elements
    • 3 elements will be displayed with titles "Own Label 4", "Own Label 5", "Own Label 6"

    So, children.length will not be refreshed until current UI's event (button onClick) has not been done.
    (I suspect that faced this situation because QML runs in one thread and all event are staying in one queue)

    Is there any way to update ".length" property immediately (to use it further in current procedure)?

    Thanks!


  • Qt Champions 2018

    My advise (as most of the time on the forum :P ), would be to not do things like you are doing.
    Manipulating UI items is not very mainenable and flexible. You should act on your data instead.

    I don't really know what is your use case, but most of the time you should avoid using Qt.createObject or Qt.createComponent and let view/models class handle the instantiation of your dynamic objects.

    In your example, you could use a Repeater with a model (an int, a js array, a ListModel, ...). I rewrote it with a ListModel :

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.12
    import QtQuick.Layouts 1.12
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        ListModel {
            id: listModel
        }
    
        ColumnLayout {
    
            RowLayout {
                Button {
                    text: qsTr("Add")
                    onClicked: listModel.append({text: listModel.count + 1})
                }
    
                Button {
                    text: qsTr("Remove")
                    onClicked: {
                        if (listModel.count > 0)
                            listModel.remove(0);
                    }
                }
    
                Button {
                    text: qsTr("Clear & Add New 3")
                    onClicked: {
                        listModel.clear();
                        for (var i = 0; i < 3; ++i) {
                            listModel.append({text: listModel.count + 1})
                        }
                    }
                }
            }
    
            ColumnLayout {
                Repeater {
                    model: listModel
                    Label { // you can replace that with OwnLabel
                        text: "My text: %1, my index: %2".arg(model.text).arg(model.index)
                    }
                }
            }
        }
    }
    

Log in to reply