当前位置: 首页 > news >正文

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

主要功能概述

允许用户在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.hskmm.com/?act=detail&tid=36791

相关文章:

  • lora学习笔记
  • 自动化释放5G全部潜力:新西兰电信One NZ的实践之路
  • cookie机制如何获取用户个人信息
  • 数据库——聚合函数
  • 第二十一篇
  • linux服务器操作系统字符集是GBK,tomcat和部署的程序是UTF-8,启动后应用界面乱码如何解决
  • DEIMv2浅读
  • 阿里出手了:全免费!号称国内版ClaudeCode?
  • [MS-DOS]MS-DOS 6.22 with CD-ROM Driver.ver.6.22.English下载与安装
  • 完整教程:2- 十大排序算法(希尔排序、计数排序、桶排序)
  • 分词器模型
  • 2025 年国内品牌设计公司最新推荐排行榜:聚焦行业领军者优势,精选优质服务商深度解析
  • 报考PostgreSQL中级认证证书多少钱?
  • 2025 年 LFT 材料源头厂家最新推荐权威榜单:复合 / 注塑 / 增强 / 轻量化 / 长碳纤 / 长玻纤 / 耐高温 LFT 材料优质公司推荐
  • Windows Server 2025 安装IIS服务
  • 易路薪酬能力深度解析:以科技赋能企业薪酬管理新范式
  • LaTeX 项目结构优化:从基础到专业
  • Java的优势有哪些
  • 传感类语音提示器语音播报芯片最佳适配方案WT2003H
  • 集合中的贡献法
  • 广州治疗青少年心理医院口碑榜:TOP3医疗机构专业实力深度解析
  • 人狗大战Ⅱ
  • 【IEEE出版、往届会后3个月检索】2025 第九届控制工程与先进算法国际论坛(IWCEAA 2025)
  • 整装定制家具生产厂家口碑榜:TOP3企业智能制造实力深度解析
  • 实用指南:阿里云安装Docker
  • 高性能超低功耗蓝牙电子价签方案 OM6626 NRF52832
  • 软工第三次作业-结对项目
  • 给大家分享三个特别好用的在线工具,可以为你的工作节省很多时间
  • 2025 年振动筛源头厂家最新推荐榜单:权威甄选实验 / 防爆 / 精细筛分设备,揭秘靠谱供应企业
  • 2025 年最新推荐摇摆筛厂家榜单:聚焦实力雄厚供货稳定品牌,助力企业精准选购筛分设备方形/圆形/石英砂/砂石/精细摇摆筛厂家推荐