问题
I have a QListWidget and a QTreeWidget and I want to be able to drag one or multiple list items around within each one as well as between them. I have the internal drag and drop working, but I'm not sure how to drag between them.
When I print event.mimeData().formats()
in my code below it says ['application/x-qabstractitemmodeldatalist']
. I am stuck on how to extract the text and index of that item (it should be a QListWidgetItem or QTreeWidgetItem, right?) so I can delete the original from the source widget and add a new item to the destination widget, how do I do that?
I tried using code from here:
https://wiki.python.org/moin/PyQt/Handling%20Qt%27s%20internal%20item%20MIME%20type
So currently my code gets a QVariant items when I drag items between the widgets, but I still don't know what to do with those to get the item text and index.
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QTreeWidgetItem
import sys
class Tree(QtWidgets.QTreeWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setDragDropMode(self.DragDrop)
self.setSelectionMode(self.ExtendedSelection)
self.setAcceptDrops(True)
for text in ['tree1','tree2','tree3']:
treeItem = QtWidgets.QTreeWidgetItem(self, [text])
treeItem.setFlags(treeItem.flags() & ~QtCore.Qt.ItemIsDropEnabled)
self.addTopLevelItem(treeItem)
def dropEvent(self, event):
if event.source() == self:
event.setDropAction(Qt.MoveAction)
QtWidgets.QTreeWidget.dropEvent(self, event)
else:
bytearray = event.mimeData().data('application/x-qabstractitemmodeldatalist')
data_items = decode_data(bytearray)
for item in data_items:
print(item)
# What do I do with this?
class List(QtWidgets.QListWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setDragDropMode(self.DragDrop)
self.setSelectionMode(self.ExtendedSelection)
self.setAcceptDrops(True)
for text in ['list1','list2','list3']:
self.addItem(text)
def dropEvent(self, event):
if event.source() == self:
event.setDropAction(Qt.MoveAction)
QtWidgets.QListWidget.dropEvent(self, event)
else:
bytearray = event.mimeData().data('application/x-qabstractitemmodeldatalist')
data_items = decode_data(bytearray)
for item in data_items:
print(item)
# What do I do with this?
def decode_data(bytearray):
data = []
item = {}
ds = QtCore.QDataStream(bytearray)
while not ds.atEnd():
row = ds.readInt32()
column = ds.readInt32()
map_items = ds.readInt32()
for i in range(map_items):
key = ds.readInt32()
value = QtCore.QVariant()
ds >> value
item[Qt.ItemDataRole(key)] = value
data.append(item)
return data
if __name__=='__main__':
app = QtWidgets.QApplication(sys.argv)
layout = QtWidgets.QHBoxLayout()
layout.addWidget(Tree())
layout.addWidget(List())
container = QtWidgets.QWidget()
container.setLayout(layout)
container.show()
app.exec_()
回答1:
You have to create the items using the information returned by decode_data which are the roles and values of each item dragged:
class Tree(QtWidgets.QTreeWidget):
# ...
def dropEvent(self, event):
if event.source() == self:
event.setDropAction(QtCore.Qt.MoveAction)
super().dropEvent(event)
elif isinstance(event.source(), QtWidgets.QListWidget):
item = self.itemAt(event.pos())
ix = self.indexAt(event.pos())
col = 0 if item is None else ix.column()
item = self.invisibleRootItem() if item is None else item
ba = event.mimeData().data('application/x-qabstractitemmodeldatalist')
data_items = decode_data(ba)
for data_item in data_items:
it = QtWidgets.QTreeWidgetItem()
item.addChild(it)
for data in data_items:
for r, v in data.items():
it.setData(col, r, v)
class List(QtWidgets.QListWidget):
# ...
def dropEvent(self, event):
if event.source() == self:
event.setDropAction(QtCore.Qt.MoveAction)
QtWidgets.QListWidget.dropEvent(self, event)
elif isinstance(event.source(), QtWidgets.QTreeWidget):
item = self.itemAt(event.pos())
row = self.row(item) if item else self.count()
ba = event.mimeData().data('application/x-qabstractitemmodeldatalist')
data_items = decode_data(ba)
for i, data_item in enumerate(data_items):
it = QtWidgets.QListWidgetItem()
self.insertItem(row+i, it)
for r, v in data_item.items():
it.setData(r,v)
来源:https://stackoverflow.com/questions/54837869/drag-items-between-qtreewidget-and-qlistwidget-in-pyqt5