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

news/2025/10/22 18:15:15/文章来源:https://www.cnblogs.com/Rrea/p/19158668

主要功能概述

允许用户在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 😃

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/943625.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决 Semi Design Upload 组件实现自定义压缩,上传文件后无法触发 onChange

背景 我们团队主要在做 C 端产品,对于 C 端应用,图片资源使用 CDN 十分重要,因此我们曾建立了一个文件上传平台:上传文件后,可以复制图片的 CDN URL 在前端项目中使用。 目前服务端不会对图片做压缩,使用前得先借…

实用指南:生活琐记(3)

实用指南:生活琐记(3)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &q…

重构商业生态:全域分销商城小程序开发赋能商家高效增长 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

设计模式-建造者模式 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

自动化释放5G全部潜力:新西兰电信One NZ的实践之路

本文详细介绍了新西兰电信运营商One New Zealand如何通过自动化技术实现5G网络转型,包括容器化平台、GitOps自动化流程和AI驱动的运维框架,大幅提升部署效率和网络可靠性。电信行业正站在新时代的门槛上。随着5G网络…

实用指南:C++设计模式_创建型模式_原型模式Prototype

实用指南:C++设计模式_创建型模式_原型模式Prototype2025-10-22 18:06 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; di…

第二十一篇

今天是10月22号,上了离散和马原。

DEIMv2浅读

DEIMv2代表了实时目标检测领域的一次重大飞跃,它通过空间调谐适配器(STA)、双轨制骨干网络设计、高效解码器优化等创新技术,成功地将DINOv3强大的视觉表示能力引入到对计算资源敏感的实时检测任务中,在精度和效率的平…

阿里出手了:全免费!号称国内版ClaudeCode?

这两年编程的开发工具层出不穷,也是一片红海,前有 Claude、CodeX,后有 Code Buddy、Qwen、Qoder 等。那问题来了,有没有一款好用、且免费的编程工具呢? 那么今天给大家分享 3 款好用且免费的编程工具。 视频分享…

[MS-DOS]MS-DOS 6.22 with CD-ROM Driver.ver.6.22.English下载与安装

下载地址: https://archive.org/details/ms-dos-6.22-with-cd-rom-driver.ver.6.22.english MS-DOS 6.22 with CD-ROM Driver.ver.6.22.English安装视频: How to Install MS-DOS on VirtualBox https://www.youtube.…

2025 年国内品牌设计公司最新推荐排行榜:聚焦行业领军者优势,精选优质服务商深度解析

引言 在当前激烈的市场竞争中,品牌设计已成为企业塑造独特形象、提升核心竞争力的关键环节。然而,品牌设计行业乱象丛生,部分企业缺乏专业体系、过度追求短期利益,导致企业难以找到靠谱的合作伙伴。为帮助企业精准…

报考PostgreSQL中级认证证书多少钱?

近几年随着PostgreSQL数据库在国内的流行,考相关认证的人也多了起来,尤其是使用PostgreSQL数据库的企业,不少员工想了解一下关于PostgreSQL数据库认证的费用、时间、题型、难度等问题,这里做些收费方面的介绍。 首…

087_尚硅谷_switch使用细节(1)

087_尚硅谷_switch使用细节(1)1.swithc细节讨论 2.case和switch 后是一个表达式(即 常量值、变量、一个有返回值的函数等都可以) 3.1.case 后的各个表达式的值的数据类型, 必须和 switch 的表达式数据类型一致,否则程…

linux服务器操作系统字符集是GBK,tomcat和部署的程序是UTF-8,启动后应用界面乱码如何解决

当 Linux 系统编码为 GBK,而 Tomcat 使用 UTF-8 时,程序界面乱码的核心原因是编码 / 解码环节不统一(如 JVM 默认编码、请求响应编码、资源文件编码等不一致)。解决需从多个层面统一编码为 UTF-8,具体步骤如下: …

2025 年感温电缆厂家最新推荐权威榜单重磅发布,全方位解析头部品牌优势助力工业消防精准选型

在工业生产、城市基建等领域,火灾安全防护是保障生命财产安全的核心环节,而感温电缆作为火灾早期探测的关键设备,其品质与性能直接决定防护效果。当前感温电缆市场品牌繁杂,既有深耕多年的老牌企业,也有新兴入局者…

完整教程:2- 十大排序算法(希尔排序、计数排序、桶排序)

完整教程:2- 十大排序算法(希尔排序、计数排序、桶排序)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consol…

预测(笔记)

概念 利用历史数据,推断未来不确定因素的方法。这是基于:过去的规律,一定会在未来不断地发生。可以应用在销售数据、经济走势、产量范围、劳动力需求等。在项目PERT中,我们用均值、方差计算出某个时间完成的概率,…

分词器模型

中文分词是NLP中一个独特且富有挑战性的任务,因为中文文本没有像英文空格那样的天然词语边界。 现代分词器模型(尤其是基于Transformer的模型如BERT、GPT等使用的中文分词器)主要采用子词分词算法,但其处理方式与英…

Windows Server 2025 安装IIS服务

2 3 3、在弹出的添角色和功能向导中选择下一步 4、选择:基于角色或基于功能的安装,然后下一步 5、选择:从服务器池中选择服务器,然后下一步 6、选择:Web服务器(IIS),在弹出的对话框选择添加功能 7、确保web服…

易路薪酬能力深度解析:以科技赋能企业薪酬管理新范式

前言:中国薪酬管理的数字化变革与易路的核心价值 在当前数字经济浪潮的推动下,中国企业的薪酬管理正经历一场前所未有的深刻变革。传统的薪酬管理模式,因其固有的效率低下、数据孤立、决策滞后等弊端,已难以适应瞬…