qt - QML:如何通过拖放重新排序转发器项目?里面有些工作代码

标签 qt drag-and-drop qml qt5

我正在尝试使用拖放对 Repeater 项目重新排序。由于动态加载的数据,我正在使用 Repeater。以下是我到目前为止使用添加了示例数据的简单 sqlite 数据库的内容。我希望的是设置重新排序,这样当用户释放拖动的对象时,数据库就会更新以反射(reflect)新的顺序。 “更改”按钮可根据需要对元素重新排序,但我无法通过拖放使其正常工作。

loadData() 函数只是创建表并插入样本数据。 “更改”按钮不会出现在最终代码中,我只是想用它来让重新排序代码起作用。

import QtQuick.Controls 2.2 as QC2
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.LocalStorage 2.0

Window {
id: root
width: 320
height: 480

property var db
property int rowHeight: 90

Component.onCompleted: {
    db = LocalStorage.openDatabaseSync("test_db", "1.0", "Database", 100000)
    loadData()
}

property var sql_data: []

function loadData() {
    var sql, rs, len, i
    db.transaction(function(tx) {
        tx.executeSql("DROP TABLE IF EXISTS tbl")
        tx.executeSql("CREATE TABLE IF NOT EXISTS tbl (
            rowId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL, listOrder INTEGER NOT NULL)")
        len = 5
        for (i = 0; i < len; i++)
            tx.executeSql("INSERT INTO tbl (name, listOrder) VALUES ('Item " + i + "', " + i + ")")
        rs = tx.executeSql("SELECT name, listOrder FROM tbl ORDER BY listOrder ASC")
    })
    len = rs.rows.length
    sql_data = new Array(len)
    for (i = 0; i < len; i++) {
        sql_data[i] = {"name": "", "order": ""}
        sql_data[i]["name"] = rs.rows.item(i).name
        sql_data[i]["order"] = rs.rows.item(i).listOrder
    }
    repeater.model = sql_data
}

Flickable {
    id: mainFlick
    anchors.fill: parent
    contentHeight: mainColumn.height

    Column {
        id: mainColumn
        width: parent.width

        QC2.Button {
            text: "Change"
            onClicked: {
                var p1, p2
                var d1 = new Date().getTime()
                var movedEle = 3
                var newPos = 1
                var ele1 = repeater.itemAt(movedEle)
                var ele2 = repeater.itemAt(newPos)
                ele1.y = ele2.y
                root.sql_data[movedEle]["order"] = root.sql_data[newPos]["order"]
                if (newPos < movedEle) {
                    p1 = newPos
                    p2 = movedEle
                } else {
                    p1 = movedEle
                    p2 = newPos
                }

                root.db.transaction(function(tx) {
                    var sql = "UPDATE tbl SET listOrder = " + root.sql_data[p1]["order"] + " "
                    sql += "WHERE listOrder = " + (root.sql_data[p2]["order"])
                    for (var i = p1; i < p2; i++) {
                        if (i !== movedEle) {
                            repeater.itemAt(i).y = repeater.itemAt(i).y + rowHeight
                            root.sql_data[i]["order"] += 1
                            sql = "UPDATE tbl SET listOrder = " + root.sql_data[i]["order"] + " "
                            sql += "WHERE listOrder = " + (root.sql_data[i]["order"] - 1)
                            tx.executeSql(sql)
                        }
                    }
                })
                sql_data = sql_data.sort(function(a,b) {
                    return a["order"] - b["order"]
                })
                repeater.model = sql_data
                var d2 = new Date().getTime()
                console.debug("Seconds: " + (d2 - d1) / 1000)
            }
        }

        Repeater {
            id: repeater
            width: parent.width
            model: []
            delegate: Column {
                id: repeaterItem
                width: parent.width - 20
                height: rowHeight
                anchors.horizontalCenter: parent.horizontalCenter
                property int pos: index

                DropArea {
                    id: dragTarget
                    width: parent.width
                    height: 20

                    Rectangle {
                        id: dropRect
                        anchors.fill: parent
                        color: "green"
                        states: [
                            State {
                                when: dragTarget.containsDrag
                                PropertyChanges {
                                    target: dropRect
                                    color: "red"
                                }
                            }

                        ]
                    }
                }

                Row {
                    id: contentRow
                    width: parent.width
                    height: parent.height
                    z: 1
                    Column {
                        id: itemColumn
                        width: parent.width - 70
                        Text {
                            text: "Name: " + modelData["name"]
                        }
                        Text {
                            text: "Order: " + modelData["order"]
                        }
                        Text {
                            text: "Repeater Index: " + index
                        }
                    } // itemColumn

                    MouseArea {
                        id: dragArea
                        width: 40
                        height: itemColumn.height

                        drag.axis: Drag.YAxis
                        drag.target: dragRect

                        onReleased: parent = ((dragRect.Drag.target !== null) ? dragRect.Drag.target : root)

                        Rectangle {
                            Component.onCompleted: console.debug(dragRect.Drag.target)
                            id: dragRect
                            width: 40
                            height: itemColumn.height
                            color: "grey"
                            Drag.active: dragArea.drag.active
                            Drag.source: dragArea
                            Drag.hotSpot.x: width / 2
                            Drag.hotSpot.y: height / 2
                            states : State {
                                when: dragArea.drag.active
                                ParentChange { target: dragRect; parent: root }
                                AnchorChanges {
                                    target: dragRect
                                    anchors.verticalCenter: undefined
                                    anchors.horizontalCenter: undefined
                                }
                            }
                        }
                    }
                } // contentRow

                Behavior on y {
                    PropertyAnimation {
                        duration: 200
                        easing.type: Easing.Linear
                    }
                }
            } // repeaterItem
        } // repeater
    } // mainColumn
} // mainFlick
} // id

大部分拖放代码来自 Qt Examples site .

这是我的问题:

  1. 用于拖动矩形的 MouseArea 似乎没有改变位置。实际移动矩形后,它会保留在新位置,但如果我想再次移动它,我必须在加载应用程序时单击并拖动它原来的位置。
  2. 如果我将拖动区域的目标从子矩形切换到整行 (repeaterItem),一切都会正确移动,但将不再与拖放区域交互。
  3. 我想我可以通过获取放置区域的 y 值,在拖动一行后获取新位置的索引。有没有更好的方法来做到这一点?

由于“更改”按钮已经对行元素进行了重新排序,我只需要帮助让行与拖放区域正确交互,然后在拖动项目时获取拖放区域的 y 位置发布。

最佳答案

它可能不是最有效的,但对于任何想做类似事情的人来说都是一个好的开始。

import QtQuick.Controls 2.2 as QC2
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQuick.LocalStorage 2.0

Window {
id: root
width: 320
height: 580

property var db
property int rowHeight: 90
property int len

Component.onCompleted: {
    db = LocalStorage.openDatabaseSync("test_db", "1.0", "Database", 100000)
    loadData()
}

property var sql_data: []

function loadData() {
    var sql, rs, i
    db.transaction(function(tx) {
        tx.executeSql("DROP TABLE IF EXISTS tbl")
        tx.executeSql("CREATE TABLE IF NOT EXISTS tbl (
            rowId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL, listOrder INTEGER NOT NULL)")
        len = 15
        for (i = 0; i < len; i++)
            tx.executeSql("INSERT INTO tbl (name, listOrder) VALUES ('Item " + i + "', " + i + ")")
        rs = tx.executeSql("SELECT name, listOrder FROM tbl ORDER BY listOrder ASC")
    })
    len = rs.rows.length
    sql_data = new Array(len)
    for (i = 0; i < len; i++) {
        sql_data[i] = {"name": "", "order": ""}
        sql_data[i]["name"] = rs.rows.item(i).name
        sql_data[i]["order"] = rs.rows.item(i).listOrder
    }
    repeater.model = sql_data
}


Flickable {
    id: mainFlick
    anchors.fill: parent
    contentHeight: mainColumn.height
    rebound: Transition {
        NumberAnimation {
            properties: "y"
            duration: 500
            easing.type: Easing.OutCirc
        }
    }

    Column {
        id: mainColumn
        width: parent.width

        function moveEle(start, end, f) {
            if (f === false) {
                var p1, p2, ele1, ele2
                var c = false
                var d1 = new Date().getTime()
                ele1 = repeater.itemAt(start)
                console.debug(f)
                ele2 = repeater.itemAt(end)
                root.sql_data[start]["order"] = root.sql_data[end]["order"]
                if (end < start) {
                    p1 = end
                    p2 = start
                } else {
                    p1 = start
                    p2 = end
                    c = true
                }

                root.db.transaction(function(tx) {
                    var sql = "UPDATE tbl SET listOrder = " + root.sql_data[p1]["order"] + " "
                    sql += "WHERE listOrder = " + (root.sql_data[p2]["order"])
                    for (var i = p1; i < p2; i++) {
                        if (c === false) {
                            if (i !== start) {
                                root.sql_data[i]["order"]++
                                sql = "UPDATE tbl SET listOrder = " + root.sql_data[i]["order"] + " "
                                sql += "WHERE listOrder = " + (root.sql_data[i]["order"] - 1)
                                tx.executeSql(sql)
                            }
                        } else {
                            root.sql_data[i]["order"]--
                            sql = "UPDATE tbl SET listOrder = " + root.sql_data[i]["order"] + " "
                            sql += "WHERE listOrder = " + (root.sql_data[i]["order"] - 1)
                            tx.executeSql(sql)
                        }
                    }
                })
            } else if (f === true) {
                c = false
                d1 = new Date().getTime()
                ele1 = repeater.itemAt(start)
                console.debug(f)
                end--
                ele2 = repeater.itemAt(end)
                root.sql_data[start]["order"] = root.sql_data[end]["order"]
                p1 = start
                p2 = end
                c = true

                root.db.transaction(function(tx) {
                    var sql = "UPDATE tbl SET listOrder = " + root.sql_data[p1]["order"] + " "
                    sql += "WHERE listOrder = " + (root.sql_data[p2]["order"])
                    tx.executeSql(sql)
                    for (var i = p1; i <= p2; i++) {
                        if (i !== start) {
                            root.sql_data[i]["order"]--
                            sql = "UPDATE tbl SET listOrder = " + root.sql_data[i]["order"] + " "
                            sql += "WHERE listOrder = " + (root.sql_data[i]["order"] - 1)
                            tx.executeSql(sql)
                        }
                    }
                })
            }

            sql_data = sql_data.sort(function(a,b) {
                return a["order"] - b["order"]
            })
            repeater.model = sql_data
            var d2 = new Date().getTime()
            console.debug("Seconds: " + (d2 - d1) / 1000)
        }

        Repeater {
            id: repeater
            width: parent.width
            model: []
            delegate: Column {
                id: repeaterItem
                width: parent.width
                height: rowHeight
                anchors.horizontalCenter: parent.horizontalCenter
                z: dragArea.drag.active ? 2 : 1
                property int pos: index

                DropArea {
                    id: dragTarget
                    width: parent.width
                    height: 15
                    property int ind: index
                    onEntered: {
                        drag.source.ind = index
                        drag.source.f = false
                        if (drag.source.ind !== drag.source.oldInd && drag.source.ind !== drag.source.oldInd + 1)
                            drag.source.caught = true
                    }
                    onExited: drag.source.caught = false

                    Rectangle {
                        id: dropRect
                        anchors.fill: parent
                        z: 0
                        states: [
                            State {
                                when: dragTarget.containsDrag
                                PropertyChanges {
                                    target: dropRect
                                    color: "grey"
                                }
                                PropertyChanges {
                                    target: dropRectLine
                                    visible: false
                                }
                            }
                        ]
                        Rectangle {
                            id: dropRectLine
                            width: parent.width
                            height: 1
                            anchors.verticalCenter: parent.verticalCenter
                            color: "black"
                        }
                    }
                }
                Row {
                    id: contentRow
                    width: parent.width
                    height: parent.height
                    Drag.active: dragArea.drag.active
                    Drag.source: dragArea
                    Drag.hotSpot.x: width / 2
                    Drag.hotSpot.y: height / 2
                    Column {
                        id: itemColumn
                        width: parent.width - 70
                        Text {
                            text: "Name: " + modelData["name"]
                        }
                        Text {
                            text: "Order: " + modelData["order"]
                        }
                        Text {
                            text: "Repeater Index: " + index
                        }
                    } // itemColumn

                MouseArea {
                    id: dragArea
                    width: 40 //repeater.width
                    height: itemColumn.height

                    drag.axis: Drag.YAxis
                    drag.target: contentRow
                    property point beginDrag
                    property point dropTarget
                    property bool caught: false
                    property int ind
                    property int oldInd: index
                    property bool f
                    onPressed: {
                        dragArea.beginDrag = Qt.point(contentRow.x, contentRow.y);
                    }
                    onReleased: {
                        if (dragArea.caught) {
                            dropRectFinal.color = "white"
                            dropRectLineFinal.visible = true
                            mainColumn.moveEle(index,dragArea.ind, dragArea.f)
                        } else {
                            backAnimY.from = contentRow.y;
                            backAnimY.to = beginDrag.y;
                            backAnim.start()
                        }
                    }

                        Rectangle {
                            id: dragRect
                            width: 40
                            height: itemColumn.height
                            color: "grey"
                        }
                    } // contentRow
                } // dragArea

                ParallelAnimation {
                    id: backAnim
                    SpringAnimation { id: backAnimY; target: contentRow; property: "y"; duration: 300; spring: 2; damping: 0.2 }
                }
            } // repeaterItem
        } // repeater

        DropArea {
            id: dragTargetFinal
            width: parent.width
            height: 15
            property int ind: root.len
            onEntered: {
                drag.source.ind = ind
                drag.source.f = true
                if (drag.source.ind !== drag.source.oldInd && drag.source.ind !== drag.source.oldInd + 1)
                    drag.source.caught = true
            }
            onExited: drag.source.caught = false

            Rectangle {
                id: dropRectFinal
                anchors.fill: parent
                states: [
                    State {
                        when: dragTargetFinal.containsDrag
                        PropertyChanges {
                            target: dropRectFinal
                            color: "grey"
                        }
                        PropertyChanges {
                            target: dropRectLineFinal
                            visible: false
                        }
                    }
                ]
                Rectangle {
                    id: dropRectLineFinal
                    width: parent.width
                    height: 1
                    anchors.verticalCenter: parent.verticalCenter
                    color: "black"
                }
            }
        }
    } // mainColumn
    QC2.ScrollBar.vertical: QC2.ScrollBar { active: scrollAnim.running ? true : false }
} // mainFlick
DropArea {
    id: scrollUp
    width: parent.width
    height: 50
    anchors.top: parent.top
    visible: {
        var visible = false
        if (mainFlick.contentY > 0)
            visible = true
        visible
    }
    onEntered: {
        scrollAnim.from = mainFlick.contentY
        scrollAnim.to = 0
        scrollAnim.start()
    }
    onExited: scrollAnim.stop()
}
DropArea {
    id: scrollDown
    width: parent.width
    height: 50
    anchors.bottom: parent.bottom
    visible: {
        var visible = false
        if (mainFlick.contentY < mainColumn.height - Window.height)
            visible = true
        visible
    }
    onEntered: {
        scrollAnim.from = mainFlick.contentY
        scrollAnim.to = mainColumn.height - Window.height
        scrollAnim.start()
    }
    onExited: scrollAnim.stop()
}
SmoothedAnimation {
    id: scrollAnim
    target: mainFlick
    property: "contentY"
    velocity: 400
    loops: 1
    maximumEasingTime: 10
}
} // root

关于qt - QML:如何通过拖放重新排序转发器项目?里面有些工作代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51792968/

相关文章:

drag-and-drop - 是否可以对 dataTransfer.files 支持进行功能测试?

qt - 使用 QML Media Player 获取慢动作视频

qt - QML 中的 64 位整数

c++ - 无法使用 QMYSQL 部署 Qt 应用程序

jQuery 选择并拖动具有相对和绝对位置的元素

c++ - QAbstractItemModel data() 永远不会被调用

java - DOCX 数据的剪贴板格式

qt - 将 qml 项添加到 Qt3DQuickWindow

windows - 如何以融合风格禁用焦点边框和背景QTreeWidget?

c++ - 如何从其他线程访问QWidget