Important: Please read the Qt Code of Conduct -

Treeview Drag and Drop row with multiple columns issue on root index

  • Hi,
    I have a treeview/QStandardItemModel with a dragDropMode set to InternalMove and a selectionBehavoir set to SelectRows. The model has three columns. The expected behavior from the user is to move the three columns in a row as a whole and rearrange the tree hierarchy as needed.

    Everything works as expected when dragging and dropping a row from column 0 on top of anther column 0. I've set the items flags on the column 1/2 items not to accept drops. The issue comes when dragging from a row to the root Item on the model and dropping in on column 1 or 2. This causes the model to create extra columns and places column 0 data in one the incorrect columns.

    How can I treat the selected row and all its items drop to always drop on column 0, when dropping on the root index?
    Do I have to re implement one of the dragDrop functions on the QStandardItemModel?


  • Lifetime Qt Champion


    What version of Qt are you using ?
    On what OS ?
    Can you provide a minimal compilable example that shows that behaviour ?

  • Hi SGaist,
    Sure, I'm on Windows 10 pro, Pyside2 v5.13.2, py3.7.6
    I was hoping to post here without python code to get more eyes on this issue than in python forum, I'm sure some of the c++ guys have ran into this before.

    So you can drop a "child" index under any parent and root index. The parents can be drop in each other. The issue is when dropping a child or parent on the root index on column 1 or 2.

    import sys
    from PySide2 import QtWidgets, QtGui
    from PySide2.QtCore import Qt
    class SnippetTreeView(QtWidgets.QTreeView):
        def __init__(self, parent=None):
            super(SnippetTreeView, self).__init__(parent)
            # self.setSortingEnabled(True)
    def create_tag_color_items():
        item_tag = QtGui.QStandardItem('tag')
        item_color = QtGui.QStandardItem('color')
        return item_tag, item_color
    def add_items(model):
        headers = [
        names = [
        for num in range(2):
            parent_item = QtGui.QStandardItem('parent-yesDrops-' + str(num))
            item_tag, item_color = create_tag_color_items()
            for name in names:
                child_item = QtGui.QStandardItem(name + '-noDrops' )
                ch_item_tag, ch_item_color = create_tag_color_items()
                parent_item.appendRow([child_item, ch_item_tag, ch_item_color])
            model.appendRow([parent_item, item_tag, item_color])
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        tree = SnippetTreeView()
        model = QtGui.QStandardItemModel()
        rec = app.exec_()

  • I did see the canDropMineData function in the model.
    How correct/safe is this approach? Am I missing any important handing of other information floating around when doing this?

    I just return a false bool on any column greater than 0.

    class DropModel(QtGui.QStandardItemModel):
        def __init__(self, parent=None):
            super(DropModel, self).__init__(parent)
        def canDropMimeData(self, data, action, row, column, parent):
            if column > 0:
                return False
            return QtGui.QStandardItemModel().canDropMimeData(data, action, row, column, parent)

  • Lifetime Qt Champion

    What about subclassing QStandardItemModel like that:

    class MyModel(QtGui.QStandardItemModel):
        def dropMimeData(self, data, action, row, column, parent):
            return super().dropMimeData(data, action, row, 0, parent)


  • Oh very nice!
    I think that was what I was looking for. Feels much cleaner.
    Thanks @SGaist !

Log in to reply