【问题标题】:Drag and Drop of subclassed QListWidgetItem子类 QListWidgetItem 的拖放
【发布时间】:2015-02-03 23:29:33
【问题描述】:

我在尝试为自定义 QListWidgetItem 实现拖放时遇到了一些问题。下面是一些示例代码:

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_())

我的自定义类 MyListWidgetItem 有一个“数据”字段,在我的真实程序中它包含一些与项目相关的信息。如果您运行代码并尝试将项目从顶部列表拖放到底部,一切正常,但如果您尝试将它们带回顶部列表,则会出现此错误:

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'

似乎很清楚,默认的拖放行为忽略了列表项已被子类化,所以我想知道哪个是处理这种情况的最佳选择。非常感谢任何帮助。 提前致谢!

【问题讨论】:

  • 不应该是getData,而不是GetData吗?

标签: python qt pyqt pyside


【解决方案1】:

我会使用 QListViewQStandardItemModel 并使用 QStandardItemModel.setItemPrototype(MyStandardItem()) 并定义 MyStandardItem 类似:

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

    def clone(self):
        return MyStandardItem()

【讨论】:

    【解决方案2】:

    如果你添加一些调试信息,如下所示,你会发现“i”已经是 MyListWidgetItem,所以这应该不是问题。

      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))
    

    输出是

    MyListWidgetItem
    

    问题是你不能将item类型转换为MyListWidgetItem,因为python不支持类型转换,所以你需要使用反射机制来调用GetData()方法,我刚刚尝试了代码,它可以工作很好!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-05
      • 1970-01-01
      • 2016-02-27
      相关资源
      最近更新 更多