I'm trying to make a treewidget that can change children between parents with the drag and drop method, but a children can never be turned in a parent. Right now this is my class:
class Tree(QTreeWidget):
def __init__(self, parent=QWidget):
QTreeWidget.__init__(self,parent)
self.setAcceptDrops(True)
self.setDragEnabled(True)
self.setDropIndicatorShown(True)
self.setEditTriggers(QAbstractItemView.AllEditTriggers)
self.setDragDropMode(QAbstractItemView.InternalMove)
self.setSelectionMode(QAbstractItemView.ExtendedSelection)
def dragMoveEvent(self, event):
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
def dropEvent(self, event):
event.setDropAction(QtCore.Qt.MoveAction)
event.accept()
target_item= self.itemAt(event.pos())
if target_item:
object_name= target_item.text(0)
if self.currentItem().parent():
parent_item= self.currentItem().parent()
parent_name = parent_item.text(0)
print("Número de Serie:", self.currentItem().text(0))
print("Solto no:",object_name)
print("Codigo de barras:",parent_name)
else:
print("Objeto de destino: ", object_name)
else:
print("Solto fora de qualquer")
So i upgrade my code and i tried to print were the child is droped and its all working but the same problem still stand´s the child when is dragged it always disapear from de treewidget and i dont know why.
Every help is welcome, thanks
Assuming we have the following tree structure, with only two levels of data:
root
├─ A
│ ├─ A1
│ └─ A2
├─ B
│ └─ B1
└─ C
Our task is as follows :
Furthermore assuming :
We can say :
This is actually possible to achieve without modifying the default QTreeWidget
's behavior - it's a question of setting the correct flags on the QTreeWidgetItem
s.
from PyQt5 import QtCore, QtWidgets
class Tree(QtWidgets.QTreeWidget):
def __init__(self, parent: QtWidgets.QWidget | None = None):
super().__init__(parent)
self.setHeaderHidden(True)
self.setAcceptDrops(True)
self.setDragEnabled(True)
self.setDropIndicatorShown(True)
self.setEditTriggers(
QtWidgets.QAbstractItemView.EditTrigger.AllEditTriggers)
self.setDragDropMode(
QtWidgets.QAbstractItemView.DragDropMode.InternalMove)
self.setSelectionMode(
QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection)
# create the `root` item, which is "fixed" and cannot be modified by user
self._root = QtWidgets.QTreeWidgetItem(self, ['.'])
self._root.setFlags(
# the root cannot be dragged and must not accept drops
~(QtCore.Qt.ItemFlag.ItemIsDropEnabled | QtCore.Qt.ItemFlag.ItemIsDragEnabled)
)
self.addTopLevelItem(self._root)
# hide the root from user
self.setRootIndex(self.indexFromItem(self._root, 0))
def add_parent(self, parent_name:str, children_names:list[str]) :
'''takes a `parent` string and it's `child` strings to populate the widget'''
# create the parent item
parent_item = QtWidgets.QTreeWidgetItem(self._root, [parent_name])
parent_item.setFlags(
# parents must allow drops, but cannot be dragged
(parent_item.flags() | QtCore.Qt.ItemFlag.ItemIsDropEnabled) & ~QtCore.Qt.ItemFlag.ItemIsDragEnabled
)
self._root.addChild(parent_item)
# create the children items
for child_name in children_names:
child_item = QtWidgets.QTreeWidgetItem(parent_item, [child_name])
child_item.setFlags(
# children can be dragged, but must not accept drops
(child_item.flags() | QtCore.Qt.ItemFlag.ItemIsDragEnabled) & ~QtCore.Qt.ItemFlag.ItemIsDropEnabled
)
parent_item.addChild(child_item)
def populate(self, data):
'''populate the widget from an initial dataset'''
for parent_name, children_names in data:
self.add_parent(parent_name, children_names)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
# create tree widget
tw = Tree()
# populate with fake data :
fakedata = [
('A', [ 'A1', 'A2' ]),
('B', [ 'B1' ]),
('C', []),
]
tw.populate(fakedata)
# run app
tw.show()
app.exec()