Drag and Drop of subclassed QListWidgetItem

元气小坏坏 提交于 2021-01-28 10:03:54

问题


I'm encountering some poblems trying to implement drag and drop for a custom QListWidgetItem. Here is some example code:

from PyQt4 import QtGui, QtCore
import sys, os


class MyListWidgetItem(QtGui.QListWidgetItem):      
    def __init__(self, label, data, parent=None):
        super(QtGui.QListWidgetItem, self).__init__(label, parent=parent)
        self.data = data

    def GetData(self):
        return self.data

class MyListWidget(QtGui.QListWidget):
    def __init__(self, type, parent=None):
        super(MyListWidget, self).__init__(parent)
        self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.setAcceptDrops(True)
        self.viewport().setAcceptDrops(True)
        self.setDropIndicatorShown(True)

    def startDrag(self, supportedActions):
        drag = QtGui.QDrag(self)
        t = [i.GetData() for i in self.selectedItems()]
        mimeData = self.model().mimeData(self.selectedIndexes())
        mimeData.setText(str(t))
        drag.setMimeData(mimeData)
        if drag.start(QtCore.Qt.MoveAction) == QtCore.Qt.MoveAction:
            for item in self.selectedItems():
                self.takeItem(self.row(item))

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls():
            event.ignore()
        else:
            event.accept()

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls():
            event.ignore()
        else:
            event.accept()

    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            event.ignore()
        if isinstance(event.source(), MyListWidget):
            event.setDropAction(QtCore.Qt.MoveAction)
            super(MyListWidget, self).dropEvent(event)
        else:
            event.ignore()

    def dropMimeData(self, index, mimedata, action):
        super(MyListWidget, self).dropMimeData(index, mimedata, action)
        return True

class Test(QtGui.QMainWindow):
    def __init__(self):
        super(QtGui.QMainWindow,self).__init__()
        myQWidget = QtGui.QWidget()
        myBoxLayout = QtGui.QVBoxLayout()
        myQWidget.setLayout(myBoxLayout)
        self.setCentralWidget(myQWidget)

        self.listWidgetA = MyListWidget(self)
        self.listWidgetB = MyListWidget(self)

        for i in range(5):
            listItemAInstance = MyListWidgetItem(str(i), i, parent=self.listWidgetA)

        myBoxLayout.addWidget(self.listWidgetA)      
        myBoxLayout.addWidget(self.listWidgetB)   

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    dialog_1 = Test()
    dialog_1.show()
    dialog_1.resize(480,320)
    sys.exit(app.exec_())

My custom class MyListWidgetItem has a 'data' field which in my real program holds some information related to the item. If you run the code and try to drag and drop items from the top list to the bottom one everything works, but if you then try to bring them back to the top list you get this error:

Traceback (most recent call last):
  File "C:\Users\Massi\Desktop\t.py", line 23, in startDrag
    t = [i.GetData() for i in self.selectedItems()]
AttributeError: 'QListWidgetItem' object has no attribute 'GetData'

It seems pretty clear that the default drag and drop behaviour ignores that the list items have been subclassed, so I wonder which is the best to deal with this situation. Any help is really appreciated. Thanks in advance!


回答1:


I would use a QListView with a QStandardItemModel and use the QStandardItemModel.setItemPrototype(MyStandardItem()) and define MyStandardItem something like:

class MyStandardItem(QtGui.QStandardItem):
    def __init__(self, *__args):
        super().__init__(*__args)

    def clone(self):
        return MyStandardItem()



回答2:


If you add some debug information like following, you could find out that the "i" is already the MyListWidgetItem, so this should not be the issue.

  def startDrag(self, supportedActions):
        drag = QtGui.QDrag(self)
        # add the following 2 line debug information
        for item in self.selectedItems():
            print item.__class__.__name__
        t = [i.GetData() for i in self.selectedItems() if hasattr(i, "GetData")]
        mimeData = self.model().mimeData(self.selectedIndexes())
        mimeData.setText(str(t))
        drag.setMimeData(mimeData)
        if drag.start(QtCore.Qt.MoveAction) == QtCore.Qt.MoveAction:
            for item in self.selectedItems():
                self.takeItem(self.row(item))

output is

MyListWidgetItem

The problem is that you can NOT cast the item type to MyListWidgetItem, as python doesn't support type cast, so you need to use reflect mechanism to call the GetData() method, I have just tried the code, it works fine !



来源:https://stackoverflow.com/questions/24392302/drag-and-drop-of-subclassed-qlistwidgetitem

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