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