Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/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?

    Thanks


  • Lifetime Qt Champion

    Hi,

    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.setContextMenuPolicy(Qt.CustomContextMenu)
            self.setDragEnabled(False)
            self.setDragDropOverwriteMode(False)
            self.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
            self.setAlternatingRowColors(True)
            self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
            # self.setSortingEnabled(True)
            self.header().setStretchLastSection(True)
            self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
    
    
    def create_tag_color_items():
        item_tag = QtGui.QStandardItem('tag')
        item_tag.setDropEnabled(False)
        item_color = QtGui.QStandardItem('color')
        item_color.setDropEnabled(False)
        return item_tag, item_color
    
    
    def add_items(model):
        headers = [
            'Name',
            'Tag',
            'Color',
        ]
        names = [
            'child-0',
            'child-1',
        ]
    
        model.setHorizontalHeaderLabels(headers)
        model.setColumnCount(len(headers))
    
        for num in range(2):
            parent_item = QtGui.QStandardItem('parent-yesDrops-' + str(num))
            parent_item.setDropEnabled(True)
            item_tag, item_color = create_tag_color_items()
    
            for name in names:
                child_item = QtGui.QStandardItem(name + '-noDrops' )
                child_item.setDropEnabled(False)
                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()
        add_items(model)
        tree.setModel(model)
        tree.show()
        rec = app.exec_()
        sys.exit(rec)
    


  • 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