Drag items between QTreeWidget and QListWidget in PyQt5?

大憨熊 提交于 2021-02-10 07:13:23

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!