问题
In my QT application I have two QTreeWidget A and B.
I want rewrite drag and drop function for this two behavior:
- From A to A move items with all childrens.
- From B to A copy items with all childrens.
I have view that in dropEvent function I have event.source() for take source.
But how change function with flag for movement or copy dinamically?
There is an example?
Thanks
回答1:
In order to perform this task we must distinguish if the action comes from himself or another widget for it is overwritten by the dropEvent
method, this returns an event of type QDropEvent
that has the method source()
that returns the object that performed the action:
def dropEvent(self, event):
if event.source() == self:
# move
else:
# copy
- From A to A move items with all childrens.
Each QTreeWidgetItem
is associated with its parent, so if it moves to the parent, the children will also move.
if event.source() == self:
event.setDropAction(Qt.MoveAction)
QTreeWidget.dropEvent(self, event)
- From B to A copy items with all childrens.
This is the most complicated task because when QTreeWidget
uses drag-and-drop it uses the mimetype x-qabstractitemmodeldatalist
that stores the information of the row and column associated to the QModelIndex of the item plus a dictionary with the roles and their values:
row_1 | column_1 | number of valid roles | role_1_1 | value_1_1 | ... | role_n_1 | value_n_1 | row_2 | column_2 | ...
so knowing the row and column it is impossible to obtain the item and therefore also your children since you must have the parent. So you should look for another strategy, the solution is to create a new mimetype where you save the necessary information to obtain the item again, the only way to do it is to save the row of the item, then the row of the parent, and then the row of parent's parent like this until you reach some topLevelItem
.
Since you already have the item you can access your children and the information they contain. The full implementation is shown below:
class TreeWidget(QTreeWidget):
customMimeType = "application/x-customTreeWidgetdata"
def mimeTypes(self):
mimetypes = QTreeWidget.mimeTypes(self)
mimetypes.append(TreeWidget.customMimeType)
return mimetypes
def startDrag(self, supportedActions):
drag = QDrag(self)
mimedata = self.model().mimeData(self.selectedIndexes())
encoded = QByteArray()
stream = QDataStream(encoded, QIODevice.WriteOnly)
self.encodeData(self.selectedItems(), stream)
mimedata.setData(TreeWidget.customMimeType, encoded)
drag.setMimeData(mimedata)
drag.exec_(supportedActions)
def dropEvent(self, event):
if event.source() == self:
event.setDropAction(Qt.MoveAction)
QTreeWidget.dropEvent(self, event)
elif isinstance(event.source(), QTreeWidget):
if event.mimeData().hasFormat(TreeWidget.customMimeType):
encoded = event.mimeData().data(TreeWidget.customMimeType)
parent = self.itemAt(event.pos())
items = self.decodeData(encoded, event.source())
for it in items:
item = QTreeWidgetItem(parent)
self.fillItem(it, item)
self.fillItems(it, item)
event.acceptProposedAction()
def fillItem(self, inItem, outItem):
for col in range(inItem.columnCount()):
for key in range(Qt.UserRole):
role = Qt.ItemDataRole(key)
outItem.setData(col, role, inItem.data(col, role))
def fillItems(self, itFrom, itTo):
for ix in range(itFrom.childCount()):
it = QTreeWidgetItem(itTo)
ch = itFrom.child(ix)
self.fillItem(ch, it)
self.fillItems(ch, it)
def encodeData(self, items, stream):
stream.writeInt32(len(items))
for item in items:
p = item
rows = []
while p is not None:
rows.append(self.indexFromItem(p).row())
p = p.parent()
stream.writeInt32(len(rows))
for row in reversed(rows):
stream.writeInt32(row)
return stream
def decodeData(self, encoded, tree):
items = []
rows = []
stream = QDataStream(encoded, QIODevice.ReadOnly)
while not stream.atEnd():
nItems = stream.readInt32()
for i in range(nItems):
path = stream.readInt32()
row = []
for j in range(path):
row.append(stream.readInt32())
rows.append(row)
for row in rows:
it = tree.topLevelItem(row[0])
for ix in row[1:]:
it = it.child(ix)
items.append(it)
return items
In the following link you will see an example
来源:https://stackoverflow.com/questions/47091216/qt-drag-and-drop-between-qtreewidget