Auf dieser Seite

QML-Tutorial zur dynamischen Anordnung in Ansichten 4 – Sortieren von Elementen

Drag & Drop ist nicht die einzige Möglichkeit, Elemente in einer Ansicht neu anzuordnen. Mithilfe eines „ DelegateModel “ ist es auch möglich, Elemente anhand von Modelldaten zu sortieren. Dazu erweitern wir unsere „ DelegateModel “-Instanz wie folgt:

    DelegateModel {
        id: visualModel
        property var lessThan: [
            function(left, right) { return left.name < right.name },
            function(left, right) { return left.type < right.type },
            function(left, right) { return left.age < right.age },
            function(left, right) {
                if (left.size == "Small")
                    return true
                else if (right.size == "Small")
                    return false
                else if (left.size == "Medium")
                    return true
                else
                    return false
            }
        ]

        property int sortOrder: orderSelector.selectedIndex
        onSortOrderChanged: items.setGroups(0, items.count, "unsorted")

        function insertPosition(lessThan, item) {
            let lower = 0
            let upper = items.count
            while (lower < upper) {
                const middle = Math.floor(lower + (upper - lower) / 2)
                const result = lessThan(item.model, items.get(middle).model)
                if (result) {
                    upper = middle
                } else {
                    lower = middle + 1
                }
            }
            return lower
        }

        function sort(lessThan) {
            while (unsortedItems.count > 0) {
                const item = unsortedItems.get(0)
                const index = insertPosition(lessThan, item)

                item.groups = "items"
                items.move(item.itemsIndex, index)
            }
        }

        items.includeByDefault: false
        groups: DelegateModelGroup {
            id: unsortedItems
            name: "unsorted"

            includeByDefault: true
            onChanged: {
                if (visualModel.sortOrder == visualModel.lessThan.length)
                    setGroups(0, count, "items")
                else
                    visualModel.sort(visualModel.lessThan[visualModel.sortOrder])
            }
        }
        model: PetsModel {}
        delegate: dragDelegate
    }
Schritt-für-Schritt-Anleitung

Elemente in einer „ DelegateModel “ werden in Gruppen gefiltert, die durch den Typ „ DelegateModelGroup “ repräsentiert werden. Normalerweise gehören alle Elemente im Modell zur Standardgruppe „ items “, doch dieser Standard kann mit der Eigenschaft „includeByDefault“ geändert werden. Um unsere Sortierung zu implementieren, möchten wir, dass Elemente zunächst einer unsortierten Gruppe hinzugefügt werden, von der aus wir sie an eine sortierte Position in der „items“-Gruppe verschieben können. Dazu löschen wir die Eigenschaft „includeByDefault“ für die „items“-Gruppe und weisen ihr den neuen Gruppennamen „unsorted“ zu.

        items.includeByDefault: false
        groups: DelegateModelGroup {
            id: unsortedItems
            name: "unsorted"

            includeByDefault: true
        }

Wir sortieren die Elemente, indem wir zunächst die Position in der Gruppe „items“ ermitteln, an der das erste unsortierte Element eingefügt werden soll, das Element dann in die Gruppe „items“ verschieben und es anschließend an den vorab festgelegten Index verschieben. Diesen Vorgang wiederholen wir, bis die Gruppe „unsorted“ leer ist.

Um die Einfügeposition für ein Element zu ermitteln, fordern wir mit der Funktion „ get()“ einen Handle für das Element aus der unsortierten Gruppe an. Über die „model“-Eigenschaft dieses Handles können wir auf dieselben Modelldaten zugreifen, die in einer Delegate-Instanz dieses Elements verfügbar sind, und diese mit anderen Elementen vergleichen, um die relative Position zu bestimmen.

        function insertPosition(lessThan, item) {
            let lower = 0
            let upper = items.count
            while (lower < upper) {
                const middle = Math.floor(lower + (upper - lower) / 2)
                const result = lessThan(item.model, items.get(middle).model)
                if (result) {
                    upper = middle
                } else {
                    lower = middle + 1
                }
            }
            return lower
        }

        function sort(lessThan) {
            while (unsortedItems.count > 0) {
                const item = unsortedItems.get(0)
                const index = insertPosition(lessThan, item)

                item.groups = "items"
                items.move(item.itemsIndex, index)
            }
        }

Das Argument „lessThan“ der Sortierfunktion ist eine Vergleichsfunktion, die die Reihenfolge der Liste festlegt. In diesem Beispiel kann es eines der folgenden sein:

        property var lessThan: [
            function(left, right) { return left.name < right.name },
            function(left, right) { return left.type < right.type },
            function(left, right) { return left.age < right.age },
            function(left, right) {
                if (left.size == "Small")
                    return true
                else if (right.size == "Small")
                    return false
                else if (left.size == "Medium")
                    return true
                else
                    return false
            }
        ]

Eine Sortierung wird immer dann ausgelöst, wenn neue Elemente zur unsortierten Gruppe „ DelegateModel “ hinzugefügt werden, worüber wir durch den Handler „ DelegateModelGroup “ onChanged benachrichtigt werden. Ist derzeit keine Sortierfunktion ausgewählt, verschieben wir einfach alle Elemente aus der unsortierten Gruppe in die Gruppe „items“; andernfalls rufen wir die Sortierfunktion mit der ausgewählten Sortierfunktion auf.

        groups: DelegateModelGroup {
            id: unsortedItems
            name: "unsorted"

            includeByDefault: true
            onChanged: {
                if (visualModel.sortOrder == visualModel.lessThan.length)
                    setGroups(0, count, "items")
                else
                    visualModel.sort(visualModel.lessThan[visualModel.sortOrder])
            }
        }

Wenn sich schließlich die ausgewählte Sortierreihenfolge ändert, können wir eine vollständige Neusortierung der Liste auslösen, indem wir alle Elemente aus der „items“-Gruppe in die „unsorted“-Gruppe verschieben. Dies löst den Handler „ DelegateModelGroup “ ( onChanged ) aus, der die Elemente in der richtigen Reihenfolge zurück in die „items“-Gruppe verschiebt. Beachten Sie, dass der Handler „ DelegateModelGroup “ ( onChanged ) nicht rekursiv aufgerufen wird, sodass es kein Problem darstellt, wenn er während einer Sortierung aufgerufen wird.

        property int sortOrder: orderSelector.selectedIndex
        onSortOrderChanged: items.setGroups(0, items.count, "unsorted")

Beispielprojekt @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.