首页 > 解决方案 > Qt Drag & Drop 不适用于自定义项目

问题描述

我正在使用带有自定义树视图小部件(MyTreeView继承自QTreeView)的 PySide2(Qt5)构建一个 GUI。模型是一个QStandardItemModel对象,而项目是自定义的:MyStandardItem,继承自QStandardItem

问题是:如果我在拖放操作后检查移动项目的类型,它已经变成了 aQStandardItem但它应该是 a MyStandardItem。我认为问题在于MimeType,经过大量研究后,我发现解决方案可能是创建自定义模型并覆盖 MIME 相关功能。我试图弄清楚怎么做,但我做不到。

所以,这里有几个问题:

对于它的价值,这里是MyStandardItem实现:

class MyStandardItem(QStandardItem):
    def __init__(self, text, font, icon_path='', value='', num=0, check_state=None):
        super().__init__()
        self.setDragEnabled(True)
        self.setDropEnabled(True)
        self.setText(text)
        self.setData({'value': (value, num)})
        self.setToolTip(str(self.data()['value']))
        self.setFont(font)
        self.setIcon(QIcon(icon_path))
        self.toggled = check_state
        if check_state is not None:
            self.setCheckable(True)
            self.setCheckState(check_state)

    def setCheckState(self, checkState):
        super().setCheckState(checkState)
        if checkState == Qt.Unchecked:
            self.toggled = Qt.Unchecked
        else:
            self.toggled = Qt.Checked

标签: pythondrag-and-droppyside2qtreeviewqstandarditemmodel

解决方案


我找到了一种无需创建自定义模型即可解决此问题的方法。

MyTreeView.dropEvent函数中:我不调用super().dropEvent()来完成拖放操作,但我通过将项目的数据复制到变量中并从这些数据创建一个新的来实现它。 MyStandardItem然后我调用insertRow()在给定位置插入新项目并deleteRow()删除旧项目。显然,移动的项目必须存储在动作开始的类属性中(DragEnterEvent())。一切都很完美。

PS:我之前已经尝试过这种方式,但我总是以空行结束。这里的不同之处在于我创建了一个新项目而不是重新插入旧项目。

这是我的代码的某些部分,以澄清我的意思。请注意,这些函数是 MyTreeView 的方法。

def dragEnterEvent(self, event: QDragEnterEvent):
    if event.source() == self:
        self.dragged_item = self.model.itemFromIndex(self.selectionModel().selectedIndexes()[0])
        super().dragEnterEvent(event)
    else:
        ...


def dropEvent(self, event: QDropEvent):
    index = self.indexAt(event.pos())
    if not index.isValid():
        return
    over_item = self.model.itemFromIndex(index)
    over_value = over_item.data()['value'][0]
    if event.source() == self:
        item_was_moved = self._move_item(over_value, over_parent_value)
        if not item_was_moved:
            return
    else:
        ...


def _move_item(self, over_value, over_parent_value):
    over_value = self._check_indicator_position(over_value)
    if over_value is None:
        return False
    dragged_parent_value = self.dragged_item.parent().data()['value'][0]
    dragged_value = self.dragged_item.data()['value'][0]
    row = self.dragged_item.row()
    items = guifunc.copy_row_items(self.dragged_item, row)
    over_value_num = int(over_value.strip('test'))
    self.dragged_item.parent().insertRow(over_value_num, items)
    if over_value_num < row:
        row += 1
    self.dragged_item.parent().removeRow(row)
    return True

推荐阅读