You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 14:56:05