I'm building a GUI using PySide2 (Qt5) with a custom treeview widget (MyTreeView
, inherited from QTreeView
). The model is a QStandardItemModel
object whereas the items are custom: MyStandardItem
, inherited from QStandardItem
.
The problem is: if I check the type of the moved item after a drag and drop action, it has become a QStandardItem
but it should have been a MyStandardItem
.
I believe that the problem is the MimeType, and after a lot of research I found out that the solution could be creating a custom model and overriding MIME related functions.
I tried to figure out how but I couldn't.
So, here are the questions:
For what it's worth, here is MyStandardItem
implementation:
class MyStandardItem(QStandardItem):
def __init__(self, text, font, icon_path='', value='', num=0, check_state=None):
super().__init__()
self.setDragEnabled(True)
self.setDropEnabled(True)
self.setText(text)
self.setData({'value': (value, num)})
self.setToolTip(str(self.data()['value']))
self.setFont(font)
self.setIcon(QIcon(icon_path))
self.toggled = check_state
if check_state is not None:
self.setCheckable(True)
self.setCheckState(check_state)
def setCheckState(self, checkState):
super().setCheckState(checkState)
if checkState == Qt.Unchecked:
self.toggled = Qt.Unchecked
else:
self.toggled = Qt.Checked
I found a way to solve this problem without having to create a custom model.
In the MyTreeView.dropEvent
function: I dont't call super().dropEvent()
to complete the drag&drop action but I implement it by myself by copying item's data in a variable and creating a new MyStandardItem
from those data. Then I call insertRow()
to insert the new item in the given position and deleteRow()
to delete the old item.
Clearly, the moved item has to be stored in a class attribute at the beginning of the action (DragEnterEvent()
).
Everything works perfectly.
PS: I've already tried this way before but I always ended up by having an empty row. The difference here is that I create a new item instead of re-inserting the old one.
Here's some parts of my code to clarify what I mean. Please, note that these functions are MyTreeView's methods.
def dragEnterEvent(self, event: QDragEnterEvent):
if event.source() == self:
self.dragged_item = self.model.itemFromIndex(self.selectionModel().selectedIndexes()[0])
super().dragEnterEvent(event)
else:
...
def dropEvent(self, event: QDropEvent):
index = self.indexAt(event.pos())
if not index.isValid():
return
over_item = self.model.itemFromIndex(index)
over_value = over_item.data()['value'][0]
if event.source() == self:
item_was_moved = self._move_item(over_value, over_parent_value)
if not item_was_moved:
return
else:
...
def _move_item(self, over_value, over_parent_value):
over_value = self._check_indicator_position(over_value)
if over_value is None:
return False
dragged_parent_value = self.dragged_item.parent().data()['value'][0]
dragged_value = self.dragged_item.data()['value'][0]
row = self.dragged_item.row()
items = guifunc.copy_row_items(self.dragged_item, row)
over_value_num = int(over_value.strip('test'))
self.dragged_item.parent().insertRow(over_value_num, items)
if over_value_num < row:
row += 1
self.dragged_item.parent().removeRow(row)
return True