Qt 拖放不适用于自定义项目

Qt Drag & Drop doesn't work fine with custom items

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

问题是:如果我在 拖放 操作后检查移动项目的类型,它已变成 QStandardItem 但它应该是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

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

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

PS:我以前已经尝试过这种方法,但我总是以空行结束。这里的区别在于我创建了一个新项目而不是 re-inserting 旧项目。

下面是我的代码的某些部分,以阐明我的意思。请注意,这些函数是 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