2

I have a number of QTreeWidget. Here, there are two trees. the left one has "a" , "b". I want to drag this item into the right tree. I have no error but the item become empty. How should I do for dragging the left data to the right tree? and why?

data is this.

b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x00\x02\x00a\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x00\x02\x00b'

from PySide import QtCore
from PySide import QtGui

import sys

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent=None)

        self.sequoia = Sequoia()
        self.baobab = Baobab()
        self.c_widget = QtGui.QWidget()
        h_boxlayout = QtGui.QHBoxLayout()
        h_boxlayout.addWidget(self.sequoia, 30)
        h_boxlayout.addWidget(self.baobab, 70)
        self.c_widget.setLayout(h_boxlayout)
        self.setCentralWidget(self.c_widget)
class Sequoia(QtGui.QTreeWidget):
    def __init__(self, parent=None):
        super(Sequoia, self).__init__(parent=None)
        self.setColumnCount(2)
        self.setAcceptDrops(True)
        self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.sampleitem = QtGui.QTreeWidgetItem()

        self.sampleitem.setText(0, "a")
        self.sampleitem.setText(1, "b")
        self.addTopLevelItem(self.sampleitem)

class Baobab(QtGui.QTreeWidget):
    def __init__(self, parent=None):
        super(Baobab, self).__init__(parent=None)
        self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.setColumnCount(2)
    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist'):
            event.accept()
        return QtGui.QTreeWidget.dragEnterEvent(self, event)
    def dragMoveEvent(self, event):

        if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist') and not isinstance(event, QtGui.QDropEvent):
            event.accept()
        return QtGui.QTreeWidget.dragMoveEvent(self, event)
    def dropEvent(self, event):
        if event.mimeData().hasFormat('application/x-qabstractitemmodeldatalist'):    
            bytearray = event.mimeData().data('application/x-qabstractitemmodeldatalist')      
            datastream = QtCore.QDataStream(bytearray, QtCore.QIODevice.ReadOnly)
            print(3306, bytearray.data())       
            item = QtGui.QTreeWidgetItem()
            item.setFlags(QtCore.Qt.ItemFlag.ItemIsEditable|QtCore.Qt.ItemFlag.ItemIsEnabled|QtCore.Qt.ItemFlag.ItemIsSelectable|QtCore.Qt.ItemIsDragEnabled|QtCore.Qt.ItemIsDropEnabled)

            item.read(datastream)
            self.addTopLevelItem(item)
def main():
    try:
        QtGui.QApplication([])
    except Exception as e:
        print(e)

    mw = MainWindow()
    mw.show()
    sys.exit(QtGui.QApplication.exec_())
if __name__ == "__main__":
    main()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Haru
  • 1,884
  • 2
  • 12
  • 30

1 Answers1

2

It is not necessary to implement your own drag-and-drop method between in QTreeWidget, you just have to configure it correctly:

from PySide import QtCore, QtGui

import sys


class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent=None)

        self.sequoia = Sequoia()
        self.baobab = Baobab()
        self.c_widget = QtGui.QWidget()
        h_boxlayout = QtGui.QHBoxLayout(self.c_widget)
        self.setCentralWidget(self.c_widget)
        h_boxlayout.addWidget(self.sequoia, 30)
        h_boxlayout.addWidget(self.baobab, 70)


class Sequoia(QtGui.QTreeWidget):
    def __init__(self, parent=None):
        super(Sequoia, self).__init__(parent=None)
        self.setColumnCount(2)
        self.setDefaultDropAction(QtCore.Qt.CopyAction)
        self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.setAcceptDrops(True)

        self.sampleitem = QtGui.QTreeWidgetItem()
        self.sampleitem.setText(0, "a")
        self.sampleitem.setText(1, "b")
        self.addTopLevelItem(self.sampleitem)


class Baobab(QtGui.QTreeWidget):
    def __init__(self, parent=None):
        super(Baobab, self).__init__(parent=None)
        self.setColumnCount(2)
        self.setAcceptDrops(True)


def main():
    app = QtGui.QApplication(sys.argv)
    mw = MainWindow()
    mw.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

If you still want to implement it manually then if we use your perspective a possible solution is:

def dropEvent(self, event):
    if event.mimeData().hasFormat(
        "application/x-qabstractitemmodeldatalist"
    ):

        ba = event.mimeData().data(
            "application/x-qabstractitemmodeldatalist"
        )
        ds = QtCore.QDataStream(
            ba, QtCore.QIODevice.ReadOnly
        )
        i = 0

        item = QtGui.QTreeWidgetItem()
        while not ds.atEnd():
            row = ds.readInt32()
            column = ds.readInt32()
            map_items = ds.readInt32()
            self.addTopLevelItem(item)
            for _ in range(map_items):
                role = ds.readInt32()
                value = ds.readQVariant()
                item.setData(i, role, value)
            i = (i + 1) % self.columnCount()

But the above is forced, a better solution is to use the dropMimeData method of the model:

def dropEvent(self, event):
    if event.mimeData().hasFormat(
        "application/x-qabstractitemmodeldatalist"
    ):

        parent = self.indexAt(event.pos())
        self.model().dropMimeData(
            event.mimeData(), event.dropAction(), 0, 0, parent
        )
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • Almost perfect. But If I don't drop my data completely, the data has been chopped... The sample data is successed by the first answer, but in my actual code, the second answer helped very much. But it has problem like that. – Haru Jun 04 '19 at 14:10