How to change position in a ColumnLayout

2019-09-14 21:12发布

问题:

I am a newbie in QML and I made a "accordion" item. I modified a not complete QML project for that. For that, I use PanelItems :

Item {
    default property var contentItem: null
    property string title: "panel"
    id: root
    Layout.fillWidth: true
    height: 30
    Layout.fillHeight: current
    property bool current: false

    ColumnLayout {

        anchors.fill: parent
        spacing: 0
        Rectangle {
            Drag.active: dragArea.drag.active
            id: bar
            Layout.fillWidth: true
            height: 30
            color:  root.current ? "#81BEF7" : "#CEECF5"
            Text {
                anchors.fill: parent
                anchors.margins: 10
                horizontalAlignment: Text.AlignLeft
                verticalAlignment: Text.AlignVCenter
                text: root.title
            }
            Text {
                anchors{
                    right: parent.right
                    top: parent.top
                    bottom: parent.bottom
                    margins: 10
                }
                horizontalAlignment: Text.AlignRight
                verticalAlignment: Text.AlignVCenter
                text: "^"
                rotation: root.current ? "180" : 0
            }
            MouseArea {
                id: dragArea
                anchors.fill: parent
                cursorShape: Qt.PointingHandCursor
                drag.axis: Drag.YAxis

                drag.target: root

                onReleased: {
                    console.log("release !")
                    root.Drag.drop()
                }
                onClicked: {
                    if (root.parent.current !== root) {
                        console.log('test');
                       // if( (root.parent.currentItem !== null) )
                         // root.parent.currentItem.current = false;
                        root.current = !root.current;

                        root.parent.currentItem = root;
                    }  
                }
            }
        }

        Rectangle {
            id: container
            Layout.fillWidth: true
            anchors.top: bar.bottom
            implicitHeight: root.height - bar.height
            clip: true
            Behavior on implicitHeight {
                PropertyAnimation { duration: 100 }
            }
        }
        Component.onCompleted: {
            if(root.contentItem !== null)
               root.contentItem.parent = container;
        }
    }
}

PanelItem.qml

Now that I succeeded, I wanted to make it possible to swap position between two different PanelItems in the ColumnLayout while using "drag and drop" functionnalities.

At this time, I can drag and drop my items but I don't know how to swap positions between my items.

Here is my main :

ApplicationWindow {
    visible: true
    width: 400
    height: 400

    ColumnLayout {
        anchors.fill: parent
        spacing: 1
        id: test
        property var currentItem: null
        PanelItem {
            title: "Panel 1"
            Rectangle {
                color: "orange"
                anchors.fill: parent
            }
        }
        PanelItem {
            title: "Panel 2"
            Rectangle {
                color: "lightgreen"
                anchors.fill: parent
            }
        }
        PanelItem {
            title: "Panel 3"
            Rectangle {
                color: "lightblue"
                anchors.fill: parent
            }
        }
        PanelItem {
            title: "Panel 4"
            Rectangle {
                color: "yellow"
                anchors.fill: parent
            }
        }
        Item {
            Layout.fillWidth: true
            Layout.fillHeight: true
        }
    }
}

main.qml

I read that I should maybe try to do it with a ListView but I can't make it works with my PanelItems.

Do you have any suggestion ? I am a bit lost with QML, Views etc.

Thanks a lot !

回答1:

You might use a Repeater and a ObjectModel to fill your ColumnLayout. There you can use the ObejctModel's move(from, to, amount)-method to rearrange the order of the objects.

To do it with drag n drop requires a little work. You need to find out, which indices are required, and maybe add some animations to make it look smooth. You might try to get the target index by using the childAt(x,y) of your column-layout, together with the drop.x, drop.y in the DropArea.onDropped-handler.

example1.qml: Use a Repeater and ObjectModel inside the ColumnLayout

ColumnLayout {
    id: test
    anchors.fill: parent
    spacing: 1
    property var currentItem: null
    Repeater {
        model: ObjectModel {
            id: om
            Button {
                text: '1'
                onClicked: om.move(ObjectModel.index, 0, 1)
                width: test.width
                height: 50
            }
            Button {
                text: '2'
                onClicked: om.move(ObjectModel.index, 0, 1)
                width: test.width
                height: 50
            }
            Button {
                text: '3'
                onClicked: om.move(ObjectModel.index, 0, 1)
                width: test.width
                height: 50
            }
            Button {
                text: '4'
                onClicked: om.move(ObjectModel.index, 0, 1)
                width: test.width
                height: 50
            }
            Button {
                text: '5'
                onClicked: om.move(ObjectModel.index, 0, 1)
                width: test.width
                height: 50
            }
            Button {
                text: '6'
                onClicked: om.move(ObjectModel.index, 0, 1)
                width: test.width
                height: 50
            }
        }
    }
}

To make everything look smooth, it might be easier to drop the ColumnLayout however and move to a ListView which is optimized for the use of models, and has transitions for adding, moving and displacing objects.

example2.qml: Replaced ColumnLayout and Repeater by ListView

ListView {
    id: test
    anchors.fill: parent
    spacing: 1
    model: ObjectModel {
        id: om
        Button {
            text: '1'
            onClicked: om.move(ObjectModel.index, 0, 1)
            width: test.width
            height: 50
        }
        Button {
            text: '2'
            onClicked: om.move(ObjectModel.index, 0, 1)
            width: test.width
            height: 50
        }
        Button {
            text: '3'
            onClicked: om.move(ObjectModel.index, 0, 1)
            width: test.width
            height: 50
        }
        Button {
            text: '4'
            onClicked: om.move(ObjectModel.index, 0, 1)
            width: test.width
            height: 50
        }
        Button {
            text: '5'
            onClicked: om.move(ObjectModel.index, 0, 1)
            width: test.width
            height: 50
        }
        Button {
            text: '6'
            onClicked: om.move(ObjectModel.index, 0, 1)
            width: test.width
            height: 50
        }
    }
}