Qt Drag and drop between QTreeWidget

六月ゝ 毕业季﹏ 提交于 2020-06-26 12:07:30

问题


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

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