Search code examples
qtqmlshufflelistmodel

Shuffle QML ListModel


I have a ListModel and a repeater. The repeater draws the Items from the ListModel, one on top of a another. That works fine so far.

Except that for on each application start I want to have a different draw order.

So i guess it would be best, to "shuffle" the ListElements in the ListModel before applying the Repeater. How can I do this?


Solution

  • Using the following answers:

    And adapting for a ListModel you get the following function:

    utils.js

    //https://stackoverflow.com/a/2450976/6622587
    function shuffle(model){
        var currentIndex = model.count, temporaryValue, randomIndex;
    
        // While there remain elements to shuffle...
        while (0 !== currentIndex) {
            // Pick a remaining element...
            randomIndex = Math.floor(Math.random() * currentIndex)
            currentIndex -= 1
            // And swap it with the current element.
            // the dictionaries maintain their reference so a copy should be made
            // https://stackoverflow.com/a/36645492/6622587
            temporaryValue = JSON.parse(JSON.stringify(model.get(currentIndex)))
            model.set(currentIndex, model.get(randomIndex))
            model.set(randomIndex, temporaryValue);
        }
        return model;
    }
    

    main.qml

    import QtQuick 2.9
    import QtQuick.Window 2.2
    import "utils.js" as Util
    
    Window {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        ListModel {
            id: fruitModel
            ListElement {
                name: "Apple"
                cost: 2.45
            }
            ListElement {
                name: "Banana"
                cost: 1.95
            }
            ListElement {
                name: "Orange"
                cost: 3.25
            }
        }
    
        Column {
            Repeater {
                model: Util.shuffle(fruitModel)
                Row {
                    spacing: 10
                    Text { text: name }
                    Text { text: '$' + cost }
                }
            }
        }
    }
    

    In this link you can find an example.