如何避免节点丢弃

时间:2017-11-28 10:41:59

标签: python pyqt pyqt5 qstandarditemmodel

在我的QtreeView我使用' QStandardItemModel`来显示具有单独属性的多个项目。我想避免该项目不会混合。例如香蕉应该可以移动到蔬菜(相同的儿童水平),但不能低于亚洲(更高的水平),移动到亚洲 - 水果是可以的(相同的儿童水平)

样品

我曾与.itemChanged合作,但似乎迟到了。我需要一个信号之前它将被删除,而 项将被删除。我尝试了eventFilter并获得了

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

但是如何获取项目的索引以便在相同的子级别中确定该项目的索引?

2 个答案:

答案 0 :(得分:0)

为了解决这个问题,我创建了一个自定义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

可以在以下link

中找到完整的示例

答案 1 :(得分:0)

以下更改允许在一行子项内移动项目,但不允许在外部移动项目。如果目标不是同一级别,仍然可以更改光标。

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()