Python 如何避免掉在节点上

Python 如何避免掉在节点上,python,pyqt,pyqt5,qstandarditemmodel,Python,Pyqt,Pyqt5,Qstandarditemmodel,在我的QtreeView中,我使用“QStandardItemModel”来显示具有单个属性的多个项目。我想避免该项目将不会混合。e、 g.香蕉应该可以移动到蔬菜(相同的儿童水平),但不低于亚洲(较高水平),移动到亚洲-水果是可以的(相同的儿童水平) 样品 我曾经使用过.itemChanged,但似乎很晚了。我需要一个信号,然后它将被删除,并且项目将被删除。我尝试了eventFilter并获得 event.type() == QtCore.QEvent.DragMove: 但是我如何获取项

在我的
QtreeView
中,我使用“QStandardItemModel”来显示具有单个属性的多个项目。我想避免该项目将不会混合。e、 g.香蕉应该可以移动到蔬菜(相同的儿童水平),但不低于亚洲(较高水平),移动到亚洲-水果是可以的(相同的儿童水平)

样品

我曾经使用过
.itemChanged
,但似乎很晚了。我需要一个信号,然后它将被删除,并且项目将被删除。我尝试了
eventFilter
并获得

event.type() == QtCore.QEvent.DragMove: 

但是我如何获取项目的索引,在该索引中项目将被删除,以确定其是否处于同一子级?

为了解决这个问题,我创建了一个自定义mimetype,它发送索引信息及其深度级别,它将只移动那些与目标的子级具有相同级别的索引

class TreeView(QTreeView):
    customMimeType = "application/x-customqstandarditemmodeldatalist"

    def __init__(self, *args, **kwargs):
        QTreeView.__init__(self, *args, **kwargs)
        self.setSelectionMode(QAbstractItemView.SingleSelection)
        self.setDragEnabled(True)
        self.viewport().setAcceptDrops(True)
        self.setDropIndicatorShown(True)
        self.setDragDropMode(QTreeView.InternalMove)

    def itemsToPixmap(self, indexes):
        rect = self.viewport().visibleRegion().boundingRect()
        pixmap = QPixmap(rect.size())
        pixmap.fill(Qt.transparent)
        painter = QPainter(pixmap)
        for index in indexes:
            painter.drawPixmap(self.visualRect(index), self.viewport().grab(self.visualRect(index)))
        return pixmap

    def mimeTypes(self):
        mimetypes = QTreeView.mimeTypes(self)
        mimetypes.append(TreeView.customMimeType)
        return mimetypes

    def startDrag(self, supportedActions):
        drag = QDrag(self)
        mimedata = self.model().mimeData(self.selectedIndexes())

        encoded = QByteArray()
        stream = QDataStream(encoded, QIODevice.WriteOnly)
        self.encodeData(self.selectedIndexes(), stream)
        mimedata.setData(TreeView.customMimeType, encoded)

        drag.setMimeData(mimedata)
        px = self.itemsToPixmap(self.selectedIndexes())
        drag.setPixmap(px)
        drag.setHotSpot(self.viewport().mapFromGlobal(QCursor.pos()) - QPoint(self.horizontalOffset(),
                                                                              self.verticalOffset()))
        drag.exec_(supportedActions)

    def encodeData(self, items, stream):
        stream.writeInt32(len(items))
        for item in items:
            p = item
            rows = []
            while p.isValid():
                rows.append(p.row())
                p = p.parent()
            stream.writeInt32(len(rows))
            for row in reversed(rows):
                stream.writeInt32(row)

    def dropEvent(self, event):
        if event.source() == self:
            if event.mimeData().hasFormat(TreeView.customMimeType):
                encoded = event.mimeData().data(TreeView.customMimeType)
                items = self.decodeData(encoded, event.source())
                ix = self.indexAt(event.pos())
                current = self.model().itemFromIndex(ix)
                p = current
                level = 1
                while p:
                    p = p.parent()
                    level += 1
                for item, ilevel in items:
                    if level == ilevel:
                        item.parent().takeRow(item.row())
                        current.appendRow(item)
                self.clearSelection()
                event.acceptProposedAction()
        else:
            event.ignore()

    def decodeData(self, encoded, tree):
        items = []
        rows = []
        stream = QDataStream(encoded, QIODevice.ReadOnly)
        while not stream.atEnd():
            nItems = stream.readInt32()
            for i in range(nItems):
                path = stream.readInt32()
                row = []
                for j in range(path):
                    row.append(stream.readInt32())
                rows.append(row)

        for row in rows:
            it = self.model().item(row[0])
            for r in row[1:]:
                it = it.child(r)
            items.append((it, len(row)))
        return items

下面是一个完整的示例,下面的更改允许在一行child中移动项目,但不允许将其移动到外部。如果目标不在同一级别,仍在更改光标

def dropEvent(self, event):
    if event.source() == self:
        if event.mimeData().hasFormat(TreeView.customMimeType):
            encoded = event.mimeData().data(TreeView.customMimeType)
            items = self.decodeData(encoded, event.source())
            ix = self.indexAt(event.pos())
            current = self.model().itemFromIndex(ix)
            p = current
            level = 0
            while p:
                p = p.parent()
                level += 1
            for item, ilevel in items:
                if level == ilevel:
                    item.parent().takeRow(item.row())
                    current.parent().insertRow(current.row(),item)
            self.clearSelection()
            event.acceptProposedAction()
    else:
        event.ignore()

我在子类化方面遇到了问题,因为我使用了
loadUIC
,通过复制设置(高度、宽度)来解决。但最重要的是,我没有找到一个解决方案,因为不再可能对条目进行排序。我尝试了
current.insertRow(current.row(),item)
,但它将其作为第一个子项插入
level
和ìlevel`是不同的,所以肯定还有其他东西……如果你通过Qt设计器创建了一个QTreeView,那么只需升级它以使用我的类。我通过
self.structureTreeModel=TreeModel()
分配它,但它在我的窗口中显示为额外的小部件。你必须升级你的QTreeWidget,请检查以下链接:我确实检查了,最后一个链接断了。所以我到处玩,最后没有收到错误信息。但是TreeView要么不可见,要么位于左上角,要么位于QtreeView小部件内部。我做了链接中提到的事情。