tach
tach

Reputation: 673

How to reorder children of QML Row (using drag and drop)?

Let's say, I have a QML Row which has some children objects (not necessarily of the same type). I would like to be able to reorder them at will. Bonus is, to be able to implement drag and drop behavior for the user. Here is a code sample, a Row with different components which I would like to reorder:

import QtQuick 2.5
import QtQuick.Controls 1.4


ApplicationWindow {
    visible: true
    width: 300
    height: 300

    Component {
        id: rect
        Rectangle {
            color: "blue"
        }
    }

    Component {
        id: rectWithText

        Rectangle {
            property alias text: txt.text
            color: "red"
            Text {
                id: txt
            }
        }
    }

    Row {
        id: r
        Component.onCompleted: {
            rect.createObject(r,{"width": 60,"height":40})
            rectWithText.createObject(r,{"width": 100,"height":40,text:"foo"})
            rect.createObject(r,{"width": 40,"height":40})
        }
    }
}

In QtWidgets, there are some functions like layout->removeWidget(widget), layout->insertWidget(index,widget) and so on, but they seem to be missing in QML.

I found some examples that used ListView/GridView and model/delegate approach, but they usually can't handle different components and thus they are not really viable as a replacement for a Row.

Is there a way to do that in QML or am I out of luck?

Upvotes: 1

Views: 1858

Answers (2)

Jens Bache-Wiig
Jens Bache-Wiig

Reputation: 96

import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.1

Window {
    visible: true

    Component {
        id: buttonComponent
        Button { text: "I'm a button" }
    }

    Component {
        id: labelComponent
        Label { text: "I'm a label" }
    }

    property var buttonModel: [buttonComponent, labelComponent, buttonComponent, buttonComponent,labelComponent]

    function shuffle(array) {
        for (var i = array.length - 1; i > 0; i--) {
            var j = Math.floor(Math.random() * (i + 1));
            var temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
        return array;
    }


    Column {
        anchors.fill: parent
        anchors.centerIn: parent
        Repeater {
            model: buttonModel
            Loader {
                sourceComponent: modelData
            }
        }
        Button {
            text: "shuffle"
            onClicked: buttonModel = shuffle(buttonModel)
        }
    }
}

You can also use a ListView in the same way. That gives you even more flexibility when animating Items.

Upvotes: 3

Jens Bache-Wiig
Jens Bache-Wiig

Reputation: 96

This is a bit of a hack but works regardless. It does not require the use of a model.

import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Controls 1.1

Window {
    visible: true
    function shuffle(array) {
        for (var i = array.length - 1; i > 0; i--) {
            var j = Math.floor(Math.random() * (i + 1));
            var temp = array[i];
            array[i] = array[j];
            array[j] = temp;
        }
        return array;
    }
    Column {
        id: column
        anchors.fill: parent
        anchors.centerIn: parent
        Button {
            text: "shuffle"
            onClicked: {
                var array = [button1, button2, button3]
                for (var a in array) { array[a].parent = null }
                array = shuffle(array)
                for (a in array) { array[a].parent = column }
            }
        }
        Button {
            id: button1
            text: "I am button 1"
        }
        Button {
            id: button2
            text: "I am button 2 "
        }
        Button {
            id: button3
            text: "I am button 3"
        }
    }
}

Upvotes: 5

Related Questions