Preserve QStandardItem subclasses in drag and drop

2019-01-20 06:28发布

问题:

I have:

self.treeView = QTreeView()
self.treeView.setObjectName("testView")
self.treeView.setDragDropMode(QAbstractItemView.InternalMove)
self.treeView.setSelectionMode(QAbstractItemView.ExtendedSelection)

itemA = SubclassQStandardItemA(self)
itemB = SubcalssQStandardItemB(self)

self.model = QStandardItemModel()
self.treeView.setModel(self.model)

self.model.appendRow(itemA)
self.model.appendRow(itemB)

When I move itemB to itemA and check its class, ItemB is no longer a SubclassQStandardItemB but a QStandardItem.

How can I keep the original class of the item when I drag and drop?

回答1:

As explained in this answer, you can use setItemPrototype to provide an item factory for a model. However, as also stated in the answer, only certain kinds of information are transferred during a drag and drop operation. For a QStandardItem, this means only the item flags and item data. There is no way to preserve the specific subclass of the item if there are multiple subclasses being used. A model can have only one prototype, and that is used for all items that are created internally by Qt.

This means you should not use multiple QStandardItem subclasses if you need to distinguish between different item types. Instead, you should use a single subclass and reimplement QStandardItem.type to distinguish between them:

class MyItem(QtGui.QStandardItem):
    TypeItemA = QtGui.QStandardItem.UserType
    TypeItemB = QtGui.QStandardItem.UserType + 1
    TypeItemC = QtGui.QStandardItem.UserType + 2

    def clone(self):
        return MyItem()

    def type(self):
        return self.data(QtCore.Qt.UserRole + 1000)

    def setType(self, value):
        self.setData(QtCore.Qt.UserRole + 1000, value)

...

itemA = MyItem(self)
itemA.setType(MyItem.TypeItemA)
itemB = MyItem(self)
itemB.setType(MyItem.TypeItemB)