PyQt:如何在dropEvent上获取QListWidget的listItem .data()

时间:2014-04-11 20:45:57

标签: python pyqt

有两个QListWidgets。使用setData(QtCore.Qt.UserRole, myClassInstA)为每个列表项分配了MyClass()的实例。

点击较低的QListWidget的listItem打印出一个点击的listItem数据,使用以下方法检索:

.data(QtCore.Qt.UserRole).toPyObject()

从顶部QListWidget拖放到下方的任何itemA显示无数据。 有趣的是,点击相同的项目打印有一个数据。我想知道是否有可能在dropsOnB()函数中检索存储在listItem中的数据(因此droppedOnB()能够打印出存储在项目中的数据)。


from PyQt4 import QtGui, QtCore
import sys, os

class MyClass(object):
        def __init__(self):
            super(MyClass, self).__init__()               

class ThumbListWidget(QtGui.QListWidget):
    _drag_info = []
    def __init__(self, type, name, parent=None):
        super(ThumbListWidget, self).__init__(parent)
        self.setObjectName(name)
        self.setIconSize(QtCore.QSize(124, 124))
        self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
        self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.setAcceptDrops(True)
        self._dropping = False

    def startDrag(self, actions):
        self._drag_info[:] = [str(self.objectName())]
        for item in self.selectedItems():
            self._drag_info.append(self.row(item))
        super(ThumbListWidget, self).startDrag(actions)

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

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls():
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
        else:
            super(ThumbListWidget, self).dragMoveEvent(event)

    def dropEvent(self, event):
        if event.mimeData().hasUrls():
            event.setDropAction(QtCore.Qt.CopyAction)
            event.accept()
            links = []
            for url in event.mimeData().urls():
                links.append(str(url.toLocalFile()))
            self.emit(QtCore.SIGNAL("dropped"), links)
        else:
            # event.setDropAction(QtCore.Qt.MoveAction)
            self._dropping = True
            super(ThumbListWidget, self).dropEvent(event)
            self._dropping = False

    def rowsInserted(self, parent, start, end):
        if self._dropping:
            self._drag_info.append((start, end))
            self.emit(QtCore.SIGNAL("dropped"), self._drag_info)
        super(ThumbListWidget, self).rowsInserted(parent, start, end)


class Dialog_01(QtGui.QMainWindow):
    def __init__(self):
        super(QtGui.QMainWindow,self).__init__()
        self.listItems={}

        myQWidget = QtGui.QWidget()
        myBoxLayout = QtGui.QVBoxLayout()
        myQWidget.setLayout(myBoxLayout)
        self.setCentralWidget(myQWidget)

        self.listWidgetA = ThumbListWidget(self, 'MainTree')
        self.listWidgetB = ThumbListWidget(self, 'SecondaryTree')
        self.listWidgetB.setDragDropMode(QtGui.QAbstractItemView.DropOnly)

        for i in range(7):
            listItemA=QtGui.QListWidgetItem()
            listItemA.setText('A'+'%04d'%i)
            self.listWidgetA.addItem(listItemA)

            myClassInstA=MyClass()
            listItemA.setData(QtCore.Qt.UserRole, myClassInstA)

            listItemB=QtGui.QListWidgetItem()
            listItemB.setText('B'+'%04d'%i)
            self.listWidgetB.addItem(listItemB)

            myClassInstB=MyClass()
            listItemB.setData(QtCore.Qt.UserRole, myClassInstB)

        myBoxLayout.addWidget(self.listWidgetA)      

        myBoxLayout.addWidget(self.listWidgetB)   
        self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.droppedOnB)
        self.listWidgetB.clicked.connect(self.itemClicked)


    def droppedOnB(self, dropped_list):
        print '\n\t droppedOnB()', dropped_list, dropped_list[-1]

        destIndexes=dropped_list[-1]
        for index in range(destIndexes[0],destIndexes[-1]+1):
            dropedItem=self.listWidgetB.item(index)
            modelIndex=self.listWidgetB.indexFromItem(dropedItem)
            dataObject = modelIndex.data(QtCore.Qt.UserRole).toPyObject()
            print '\n\t\t droppedOnB()', type(modelIndex), type(dataObject)

    def itemClicked(self, modelIndex):      
        dataObject = modelIndex.data(QtCore.Qt.UserRole).toPyObject()
        print 'itemClicked(): ' ,type(modelIndex), type(dataObject)


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

1 个答案:

答案 0 :(得分:0)

最终目标是在将itemA删除到listWidgetB之后,将 MyClassA 的实例数据 - 对象(附加到itemA)替换为 MyClassB

当itemA被放到目标listWidgetB上时,itemA到达时没有存储数据。如果您尝试使用itemA.data(QtCore.Qt.UserRole).toPyObject()检索它,则返回None(如果在droppedOnB()内部完成 - 首先触发onDrop事件的方法)。

尝试分配,重新分配数据到刚删除的listItem ...甚至删除它会导致以后出现各种意外。我正在使用.setHidden(True)。

这些是步骤:

  1. 获取源listItem及其数据。
  2. 获取目的地(已删除)项并将其隐藏。
  3. 声明MyClassB()实例
  4. 创建新的列表项。使用.setData(QtCore.Qt.UserRole,myClassInstB)将上一步中创建的分配MyClassB()实例对象分配给listItem
  5. 将新listItem添加到ListWidget。
  6. 这是一个功能代码。 itemA再次在创建时分配ClassA的实例。 将itemA拖放到listWidgetB后,隐藏的项目将被隐藏,并被另一个分配了classB实例的项目“替换”。

    from PyQt4 import QtGui, QtCore
    import sys, os, copy
    
    class MyClassA(object):
            def __init__(self):
                super(MyClassA, self).__init__()               
    
    class MyClassB(object):
            def __init__(self):
                super(MyClassB, self).__init__()
                self.DataObjectCopy=None  
    
    class ThumbListWidget(QtGui.QListWidget):
        _drag_info = []
        def __init__(self, type, name, parent=None):
            super(ThumbListWidget, self).__init__(parent)
            self.setObjectName(name)
            self.setIconSize(QtCore.QSize(124, 124))
            self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
            self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
            self.setAcceptDrops(True)
            self._dropping = False
    
        def startDrag(self, actions):
            self._drag_info[:] = [str(self.objectName())]
            for item in self.selectedItems():
                self._drag_info.append(self.row(item))
            super(ThumbListWidget, self).startDrag(actions)
    
        def dragEnterEvent(self, event):
            if event.mimeData().hasUrls():
                event.accept()
            else:
                super(ThumbListWidget, self).dragEnterEvent(event)
    
        def dragMoveEvent(self, event):
            if event.mimeData().hasUrls():
                event.setDropAction(QtCore.Qt.CopyAction)
                event.accept()
            else:
                super(ThumbListWidget, self).dragMoveEvent(event)
    
        def dropEvent(self, event):
            if event.mimeData().hasUrls():
                event.setDropAction(QtCore.Qt.CopyAction)
                event.accept()
                links = []
                for url in event.mimeData().urls():
                    links.append(str(url.toLocalFile()))
                self.emit(QtCore.SIGNAL("dropped"), links)
            else:
                # event.setDropAction(QtCore.Qt.MoveAction)
                self._dropping = True
                super(ThumbListWidget, self).dropEvent(event)
                self._dropping = False
    
        def rowsInserted(self, parent, start, end):
            if self._dropping:
                self._drag_info.append((start, end))
                self.emit(QtCore.SIGNAL("dropped"), self._drag_info)
            super(ThumbListWidget, self).rowsInserted(parent, start, end)
    
    
    class Dialog_01(QtGui.QMainWindow):
        def __init__(self):
            super(QtGui.QMainWindow,self).__init__()
            self.listItems={}
    
            myQWidget = QtGui.QWidget()
            myBoxLayout = QtGui.QVBoxLayout()
            myQWidget.setLayout(myBoxLayout)
            self.setCentralWidget(myQWidget)
    
            self.listWidgetA = ThumbListWidget(self, 'MainTree')
            self.listWidgetB = ThumbListWidget(self, 'SecondaryTree')
            self.listWidgetB.setDragDropMode(QtGui.QAbstractItemView.DropOnly)
    
            for i in range(3):
                listItemA=QtGui.QListWidgetItem()
                listItemA.setText('A'+'%04d'%i)
                self.listWidgetA.addItem(listItemA)
    
                myClassInstA=MyClassA()
                listItemA.setData(QtCore.Qt.UserRole, myClassInstA)
    
                listItemB=QtGui.QListWidgetItem()
                listItemB.setText('B'+'%04d'%i)
                self.listWidgetB.addItem(listItemB)
    
                myClassInstB=MyClassB()
                listItemB.setData(QtCore.Qt.UserRole, myClassInstB)
    
            myBoxLayout.addWidget(self.listWidgetA)      
    
            myBoxLayout.addWidget(self.listWidgetB)   
            self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.droppedOnB)
            self.listWidgetB.clicked.connect(self.itemClicked)
    
    
        def droppedOnB(self, dropped_list):
            if not dropped_list or len(dropped_list)<3: return       
    
            srcIndexes=dropped_list[1:-1]
            destIndexes=dropped_list[-1]
    
            # build a list of corresponding src-to-dest indexes sets
            itemsIndxes=[]
            i=0
            for num in range(destIndexes[0], destIndexes[-1]+1):
                itemsIndxes.append((srcIndexes[i], num))
                i+=1 
    
            print '\n\t droppedOnB(): dropped_list =',dropped_list,'; srcIndexes =',srcIndexes,'; destIndexes =',destIndexes, '; itemsIndxes =',itemsIndxes
    
            for indexSet in itemsIndxes:
                srcNum = indexSet[0]
                destIndxNum = indexSet[-1]
    
                # Get source listItem's data object
                srcItem=self.listWidgetA.item(srcNum)
                if not srcItem: continue
                srcItemData = srcItem.data(QtCore.Qt.UserRole)
                if not srcItemData: continue
                srcItemDataObject=srcItemData.toPyObject()
                if not srcItemDataObject: continue
                # make a deepcopy of src data object
                itemDataObject_copy=copy.deepcopy(srcItemDataObject)
    
                # get dropped item
                droppedItem=self.listWidgetB.item(destIndxNum)
                # hide dropped item since removing it results to mess
                droppedItem.setHidden(True)
                # declare new ClassB instance
                myClassInstB=MyClassB()
                myClassInstB.DataObjectCopy=itemDataObject_copy
    
                # create a new listItem
                newListItem=QtGui.QListWidgetItem()
                newListItem.setData(QtCore.Qt.UserRole, myClassInstB)
                newListItem.setText(srcItem.text())
                self.listWidgetB.blockSignals(True)
                self.listWidgetB.addItem(newListItem)
                self.listWidgetB.blockSignals(False)
    
    
        def itemClicked(self, modelIndex):      
            dataObject = modelIndex.data(QtCore.Qt.UserRole).toPyObject()
            print 'itemClicked(): instance type:', type(dataObject)
    
    
    if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        dialog_1 = Dialog_01()
        dialog_1.show()
        dialog_1.resize(720,480)
        sys.exit(app.exec_())