尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

QT实现QTreeWidget项目拖拽移动功能

QT实现QTreeWidget项目拖拽移动功能
📅 发布时间:2026/6/20 13:36:47

主要功能概述

允许用户在QTreeWidget内部拖拽项目

拖拽时显示确认对话框

程序环境

Python 3.8.9
pyside6==6.1.3

pip install pyside6==6.1.3

实现效果

20251022_175428

demo代码获取

Gitee:treewidget-demo

百度网盘:https://pan.baidu.com/s/1rDrZUyrjrqmDrFVSdUgbQA?pwd=hp9b

代码实现

以下是完整的实现代码:

from PySide6.QtCore import Qt
from PySide6.QtWidgets import QMessageBox, QAbstractItemView
import sys
from untitled2 import *class MainWindow(QMainWindow, Ui_Form):def __init__(self):super().__init__()central_widget = QWidget()self.setCentralWidget(central_widget)self.setupUi(central_widget)# 设置拖放属性self.file_list.setDragEnabled(True)self.file_list.setAcceptDrops(True)self.file_list.setDragDropMode(QAbstractItemView.InternalMove)# 重写 dropEventdef new_drop_event(event: QDropEvent):source = event.source()if source is not self.file_list:event.ignore()return# 获取目标位置target_index = self.file_list.indexAt(event.position().toPoint())if not target_index.isValid():event.ignore()return# 获取所有选中的项目(不只是 currentItem)selected_items = self.file_list.selectedItems()if not selected_items:event.ignore()return# 获取目标项目target_item = self.file_list.itemFromIndex(target_index)# 显示确认对话框target_name = target_item.text(0) if target_item else "列表末尾"reply = QMessageBox.question(self,"确认移动",f"确定要将项目: {len(selected_items)}个项目\n移动到: {target_name} 之前吗?",QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)if reply != QMessageBox.StandardButton.Yes:event.ignore()returnif event.proposedAction() == Qt.MoveAction:print(f"移动 {len(selected_items)} 个项目")# 如果是移动到目标项目上(覆盖)if target_item:print(f"覆盖到 {target_item.text(0)}")# 获取目标位置的行号target_row = target_index.row()# 克隆所有选中的项目并插入到目标位置parent = self.file_list.invisibleRootItem()for i, item in enumerate(selected_items):new_item = item.clone()  # 复制项目parent.insertChild(target_row + i, new_item)else:# 直接移动所有项目到末尾parent = self.file_list.invisibleRootItem()for item in selected_items:parent.addChild(item.clone())  # 或者直接移动 itemevent.accept()  # 接受事件,阻止默认行为else:event.ignore()self.file_list.dropEvent = new_drop_event# 正确连接信号的方式self.file_list.model().rowsAboutToBeRemoved.connect(self.on_rows_about_to_be_removed)# 用于跟踪移动的临时变量self.moved_items_cache = []def on_rows_about_to_be_removed(self, parent: QModelIndex, start: int, end: int):"""在项目被移除前缓存被移动的项目"""if not parent.isValid():  # 只处理顶级项目self.moved_items_cache = []for i in range(start, end + 1):item = self.file_list.topLevelItem(i)if item:self.moved_items_cache.append(item.text(0))print(self.moved_items_cache)print("移动至位置start",start,end)if __name__ == "__main__":app = QApplication(sys.argv)window = MainWindow()window.show()sys.exit(app.exec())

代码解析

1. 初始化设置

# 设置拖放属性
self.file_list.setDragEnabled(True)
self.file_list.setAcceptDrops(True)
self.file_list.setDragDropMode(QAbstractItemView.InternalMove)

这三行代码启用了QTreeWidget的拖放功能,并设置为内部移动模式(InternalMove),这意味着只允许在控件内部进行拖拽操作。

2. 重写dropEvent

重写了QTreeWidget的dropEvent方法,以实现自定义的拖放逻辑:

def new_drop_event(event: QDropEvent):# 检查来源是否是当前控件source = event.source()if source is not self.file_list:event.ignore()return

首先检查拖拽事件的来源,如果不是来自当前QTreeWidget,则忽略该事件。

3. 获取目标位置

通过indexAt方法获取鼠标释放位置对应的项目索引,如果位置无效则忽略事件。

# 获取目标位置
target_index = self.file_list.indexAt(event.position().toPoint())
if not target_index.isValid():event.ignore()return

4. 获取选中项目

获取所有被选中的项目,而不是仅获取当前项目(currentItem),这样可以支持多选拖拽。

# 获取所有选中的项目(不只是 currentItem)
selected_items = self.file_list.selectedItems()
if not selected_items:event.ignore()return

5. 显示确认对话框

在移动前显示确认对话框,显示将要移动的项目数量和目标位置。

# 显示确认对话框
target_name = target_item.text(0) if target_item else "列表末尾"reply = QMessageBox.question(self,"确认移动",f"确定要将项目: {len(selected_items)}个项目\n移动到: {target_name} 之前吗?",QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
)if reply != QMessageBox.StandardButton.Yes:event.ignore()return

6. 处理移动逻辑

根据拖拽动作类型处理移动逻辑:

  • 如果是移动动作(MoveAction),则克隆选中的项目并插入到目标位置
  • 如果目标位置无效,则将项目添加到末尾
if event.proposedAction() == Qt.MoveAction:print(f"移动 {len(selected_items)} 个项目")# 如果是移动到目标项目上(覆盖)if target_item:print(f"覆盖到 {target_item.text(0)}")# 获取目标位置的行号target_row = target_index.row()# 克隆所有选中的项目并插入到目标位置parent = self.file_list.invisibleRootItem()for i, item in enumerate(selected_items):new_item = item.clone()  # 复制项目parent.insertChild(target_row + i, new_item)else:# 直接移动所有项目到末尾parent = self.file_list.invisibleRootItem()for item in selected_items:parent.addChild(item.clone())  # 或者直接移动 itemevent.accept()  # 接受事件,阻止默认行为
else:event.ignore()

7. 跟踪项目移动

连接rowsAboutToBeRemoved信号到自定义槽函数,用于跟踪被移动的项目。

# 连接信号
self.file_list.model().rowsAboutToBeRemoved.connect(self.on_rows_about_to_be_removed)# 跟踪变量
self.moved_items_cache = []

在项目被移除前,缓存这些项目的文本内容,可用于后续的操作。

def on_rows_about_to_be_removed(self, parent: QModelIndex, start: int, end: int):"""在项目被移除前缓存被移动的项目"""if not parent.isValid():  # 只处理顶级项目self.moved_items_cache = []for i in range(start, end + 1):item = self.file_list.topLevelItem(i)if item:self.moved_items_cache.append(item.text(0))print(self.moved_items_cache)print("移动至位置start",start,end)

END 😃

相关新闻

  • 重构商业生态:全域分销商城小程序开发赋能商家高效增长 - 实践
  • 阿里出手了:全免费!号称国内版ClaudeCode?
  • 报考PostgreSQL中级认证证书多少钱?

最新新闻

  • 零投诉零纠纷!2026沈阳黄金回收标杆品牌合扬实力认证 - 奢侈品交易观察员
  • 夸克网盘链接解析直链链接_在线解析网盘链接
  • 【图像隐写】基于DWT、SVD和扩频技术混合可见-隐形水印系统(将彩色标志和强大的隐藏水印嵌入图像中附Matlab代码
  • Qwen3-VL技术报告实操解剖:双塔对齐、动态桥接与工业级微调指南
  • HDRI转立方体贴图终极指南:3步让3D场景光照真实感翻倍
  • 5分钟搞定M3U8视频下载:免费工具让加密视频轻松保存

日新闻

  • 信任的进化:技术实现详解——如何用JavaScript构建博弈论模拟器
  • Terrakube自定义工作流:如何集成OPA、Infracost等工具扩展IaC能力
  • grunt-concurrent快速入门:5分钟学会并行运行Grunt任务

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号