QTreeWidget仅顶层项内部拖拽的实现及后续处理需求
PyQt5 QTreeWidget 拖拽限制与拖拽后更新方案
核心结论
重写dropEvent完全可行,且是实现「拖拽完成后更新索引并保存数据库」需求的核心方式。结合重写其他拖拽相关事件,可同时满足所有三个需求。
需求实现方案
1. 仅允许拖拽顶层项
通过重写startDrag方法,判断选中项是否为顶层项,非顶层项直接终止拖拽流程:
def startDrag(self, actions): selected_item = self.currentItem() # 检查是否为顶层项(indexOfTopLevelItem返回-1表示非顶层) if selected_item and self.indexOfTopLevelItem(selected_item) != -1: super().startDrag(actions) else: return
同时配合项的flags设置:只为顶层项添加Qt.ItemIsDragEnabled,子项不设置该属性。
2. 禁止将项作为子项拖入其他项
重写dragMoveEvent,拦截目标为子项或要放入子项位置的拖拽操作:
def dragMoveEvent(self, event): target_index = self.indexAt(event.pos()) if target_index.isValid(): target_item = self.itemFromIndex(target_index) # 目标是子项,或拖拽位置是要放入目标项内部(OnItem),则拒绝 if target_item.parent() is not None or self.dropIndicatorPosition() == QAbstractItemView.OnItem: event.ignore() return super().dragMoveEvent(event)
3. 拖拽完成后更新索引并保存至SQLite
在重写的dropEvent中,先完成默认拖拽逻辑,再执行索引更新和数据库保存:
def dropEvent(self, event): # 先执行默认拖拽移动操作 super().dropEvent(event) # 更新树部件指定列的附录索引 self.updateAppendixIndex() # 将变更保存到SQLite数据库 self.saveToDatabase() def updateAppendixIndex(self): # 示例:更新第1列的附录索引(可根据实际列调整) for idx in range(self.topLevelItemCount()): item = self.topLevelItem(idx) item.setText(1, f"附录 {idx+1}") def saveToDatabase(self): # 连接数据库(请根据实际路径调整) conn = sqlite3.connect('tree_config.db') cursor = conn.cursor() # 示例逻辑:清空旧数据后插入新索引(实际可改为根据项ID更新) cursor.execute("DELETE FROM top_level_items") for idx in range(self.topLevelItemCount()): item = self.topLevelItem(idx) item_id = item.text(0) # 假设第0列是项的唯一ID appendix_idx = idx + 1 cursor.execute( "INSERT INTO top_level_items (item_id, appendix_index) VALUES (?, ?)", (item_id, appendix_idx) ) conn.commit() conn.close()
完整自定义TreeWidget示例
from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAbstractItemView from PyQt5.QtCore import Qt import sqlite3 class CustomTreeWidget(QTreeWidget): def __init__(self, parent=None): super().__init__(parent) self.setDragDropMode(QAbstractItemView.InternalMove) self.setSelectionMode(QAbstractItemView.SingleSelection) def startDrag(self, actions): selected_item = self.currentItem() if selected_item and self.indexOfTopLevelItem(selected_item) != -1: super().startDrag(actions) else: return def dragMoveEvent(self, event): target_index = self.indexAt(event.pos()) if target_index.isValid(): target_item = self.itemFromIndex(target_index) if target_item.parent() is not None or self.dropIndicatorPosition() == QAbstractItemView.OnItem: event.ignore() return super().dragMoveEvent(event) def dropEvent(self, event): super().dropEvent(event) self.updateAppendixIndex() self.saveToDatabase() def updateAppendixIndex(self): for idx in range(self.topLevelItemCount()): item = self.topLevelItem(idx) item.setText(1, f"附录 {idx+1}") def saveToDatabase(self): conn = sqlite3.connect('tree_config.db') cursor = conn.cursor() # 确保表存在(首次运行时创建) cursor.execute(""" CREATE TABLE IF NOT EXISTS top_level_items ( item_id TEXT PRIMARY KEY, appendix_index INTEGER ) """) cursor.execute("DELETE FROM top_level_items") for idx in range(self.topLevelItemCount()): item = self.topLevelItem(idx) cursor.execute( "INSERT INTO top_level_items (item_id, appendix_index) VALUES (?, ?)", (item.text(0), idx+1) ) conn.commit() conn.close()
内容的提问来源于stack exchange,提问作者Chris P
相关产品推荐
相关产品推荐

