大连密封材料 发表于 6 天前

QML ListView:实现可拖拽排序的组件

引言

在现代UI设计中,可拖拽排序的列表视图是一种常见且实用的交互方式。用户可以通过简单的拖拽操作来调整列表项的顺序,从而实现更加直观且高效的数据管理。本文将以一个简单的QML项目为例,详细先容怎样在Qt Quick中实现一个可拖拽排序的ListView组件。通过本文的学习,读者可以掌握Qt中拖放操作的基本原理、状态管理以及动画效果的实现方法。
相干阅读



[*]QML ListView:列表视图的数据交互与样式定制
[*]QML与C++:基于ListView调用外部模型进行增编削查(附自定义组件)
[*]QML与C++:基于ListView调用外部模型进行增编削查(性能优化版)
工程结构

该项目接纳了Qt的CMake构建体系,重要由QML文件和C++启动代码组成。项目结构如下:
   各文件的功能说明:


[*]main.cpp:程序入口,负责创建Qt应用实例和加载QML模块
[*]CMakeLists.txt:CMake构建脚本,设置项目编译选项和依赖
[*]Main.qml:主窗口,包罗应用的基本结构
[*]DraggableListView.qml:自定义可拖拽ListView组件的实现
示例代码详解

主窗口(Main.qml)

import QtQuick
import QtQuick.Window

Window {
    width: 400
    height: 600
    visible: true
    title: "可拖拽列表示例"

    DraggableListView {
      anchors.fill: parent
      anchors.margins: 10
    }
}
Main.qml定义了应用程序的主窗口,它非常简洁:


[*]导入必要的QtQuick和QtQuick.Window模块
[*]窗口中放置一个DraggableListView组件,填充整个窗口地域并设置10像素的边距
可拖拽列表视图(DraggableListView.qml)

import QtQuick
import QtQuick.Controls

// 可拖拽列表视图组件
ListView {
    id: listView

    // 基础属性设置
    width: parent.width
    height: parent.height
    spacing: 5
    clip: true
    interactive: true

    // 列表数据模型
    model: ListModel {
      id: listModel
      ListElement { name: "项目 1"; colorCode: "#FFB6C1" }
      ListElement { name: "项目 2"; colorCode: "#98FB98" }
      ListElement { name: "项目 3"; colorCode: "#87CEEB" }
      ListElement { name: "项目 4"; colorCode: "#DDA0DD" }
    }

    // 列表项委托
    delegate: Item {
      id: delegateItem
      width: listView.width
      height: 60

      required property int index
      required property string name
      required property string colorCode

      // 可拖拽矩形
      Rectangle {
            id: dragRect
            anchors.margins: 5
            color: colorCode
            radius: 5
            border {
                color: "gray"
                width: 1
            }

            // 拖拽相关属性
            Drag.active: dragArea.drag.active
            Drag.source: delegateItem
            Drag.hotSpot {
                x: width / 2
                y: height / 2
            }

            // 拖拽状态管理
            states: [
                State {
                  name: "dragging"
                  when: dragArea.drag.active
                  ParentChange {
                        target: dragRect
                        parent: listView
                  }
                  PropertyChanges {
                        target: dragRect
                        anchors {
                            left: undefined
                            right: undefined
                            top: undefined
                            bottom: undefined
                        }
                        width: delegateItem.width - 10
                        height: delegateItem.height - 10
                        z: 2
                  }
                },
                State {
                  name: "normal"
                  when: !dragArea.drag.active
                  ParentChange {
                        target: dragRect
                        parent: delegateItem
                  }
                  PropertyChanges {
                        target: dragRect
                        anchors {
                            left: parent.left
                            right: parent.right
                            top: parent.top
                            bottom: parent.bottom
                            margins: 5
                        }
                        x: 0
                        y: 0
                  }
                }
            ]

            // 显示文本
            Text {
                anchors.centerIn: parent
                text: name
                font.pixelSize: 16
            }

            // 拖拽区域
            MouseArea {
                id: dragArea
                anchors.fill: parent
                drag.target: dragRect
                drag.axis: Drag.YAxis
                cursorShape: Qt.PointingHandCursor

                property int startIndex: -1
                property bool held: false

                onPressed: {
                  held = true
                  startIndex = delegateItem.index
                }

                onReleased: {
                  held = false
                  var dropPos = mapToItem(listView, mouseX, mouseY)
                  var dropIndex = listView.indexAt(dropPos.x, dropPos.y)
                  
                  if (dropIndex >= 0 && dropIndex < listModel.count && dropIndex !== startIndex) {
                        listModel.move(startIndex, dropIndex, 1)
                  }
                }
            }
      }
    }

    // 位移动画
    displaced: Transition {
      NumberAnimation {
            properties: "x,y"
            duration: 200
            easing.type: Easing.OutQuad
      }
    }
}
这是本项目的焦点组件,实现了可拖拽排序的ListView。以下是代码详解:
根本结构



[*]这个组件继承自Qt Quick的标准ListView控件
[*]设置了基本的尺寸、间距和交互属性
[*]利用ListModel作为数据源,包罗4个示例项目,每个项目闻名称和颜色代码两个属性
列表项委托



[*]每个列表项都是一个自定义的Item
[*]通过required property声明属性,以吸取来自模型的数据
[*]列表项中包罗一个可视化的Rectangle,表现颜色和文本内容
拖拽功能实现

拖拽属性设置:


[*]利用Drag.active指定何时处于拖拽状态
[*]Drag.source指定拖拽源对象
[*]Drag.hotSpot定义拖拽热点位置
状态管理:


[*]"dragging"状态:当用户拖拽项目时,重设父对象为ListView,移除锚点约束,调整大小并提高Z轴顺序
[*]"normal"状态:非拖拽状态下,规复正常的结构和父子关系
拖拽交互:


[*]利用MouseArea实现拖拽举动
[*]限定拖拽方向为Y轴(垂直方向)
[*]记载拖拽开始时的索引位置
[*]在释放时计算拖放位置,通过mapToItem转换坐标系
[*]利用ListView.indexAt获取目的索引位置
[*]最后调用ListModel.move方法实现列表项的重新排序
动画效果



[*]利用ListView的displaced属性定义位移动画
[*]当列表项因拖拽操作被移动时应用平滑过渡
[*]动画连续200毫秒,利用OutQuad缓动效果
运行效果

https://i-blog.csdnimg.cn/direct/8292a6cc67694b5381f6d828ec47fcb3.gif
总结

本文通过一个简单的例子展示了怎样在Qt Quick中实现可拖拽排序的ListView组件。重要技能点包括:

[*]利用Qt的拖放(Drag and Drop)机制实现列表项拖拽
[*]利用状态(States)管理拖拽过程中的视觉反馈
[*]通过坐标映射确定拖放位置
[*]利用模型的move方法实现数据重排
[*]添加动画效果提升用户体验
这种可拖拽排序的列表视图在很多应用中都有广泛的应用场景,比如待办事项管理、播放列表编辑、文件排序等。
下载链接

完整代码可在以下链接下载:GitCode ListView示例
https://i-blog.csdnimg.cn/direct/f4ecfa9ecd9442498c702cf6289d5672.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: QML ListView:实现可拖拽排序的组件