python - 如何从一个 QListWidget 拖放到另一个

标签 python pyqt4 qlistwidget

同一个对话窗口中有两个 QListWIdget。两者都启用了 DragDrop 功能。如果我将文件拖放到两个 ListWidges 中的任何一个,程序会识别它并打印出拖放文件的列表。但是除了拖放文件之外,我希望能够将列表小部件项目从一个拖放到另一个。如果我拖动 ListItems,则会触发拖放事件。但是它无法识别哪些项目被放到了小部件上。示例代码如下。目标是将列表项从一个 ListWidget 拖放到另一个。

import sys, os
from PyQt4 import QtCore, QtGui   
class ThumbListWidget(QtGui.QListWidget):
    def __init__(self, type, parent=None):
        super(ThumbListWidget, self).__init__(parent)
        self.setAcceptDrops(True)
        self.setIconSize(QtCore.QSize(124, 124))

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

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

    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.ignore()


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)
        for i in range(12): 
            QtGui.QListWidgetItem( 'Item '+str(i), self.listWidgetA )
        myBoxLayout.addWidget(self.listWidgetA)

        self.listWidgetB = ThumbListWidget(self)
        myBoxLayout.addWidget(self.listWidgetB)   

        self.listWidgetA.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.listWidgetA.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.connect(self.listWidgetA, QtCore.SIGNAL("dropped"), self.items_dropped)
        self.listWidgetA.currentItemChanged.connect(self.item_clicked)

        self.listWidgetB.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.listWidgetB.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.items_dropped)
        self.listWidgetB.currentItemChanged.connect(self.item_clicked)

    def items_dropped(self, arg):
        print arg

    def item_clicked(self, arg):
        print arg

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

编辑#2

这是完成这一切的代码。但是没有办法追踪掉落的是什么物体。 droppedOnA() 和 droppedOnB() 方法仍然不起作用。


from PyQt4 import QtGui, QtCore
import sys, os


class MyClassItem(QtGui.QListWidgetItem):
    def __init__(self, parent=None):
        super(QtGui.QListWidgetItem, self).__init__(parent)       


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

    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):
        print 'dropEvent', 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)
            super(ThumbListWidget, self).dropEvent(event)


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)
        self.listWidgetB = ThumbListWidget(self)

        for i in range(7):
            listItemAInstance=MyClassItem()
            listItemAInstance.setText('A'+'%04d'%i)
            listItemAInstance.setBackgroundColor(QtCore.Qt.darkGray)   
            if i%2: listItemAInstance.setBackgroundColor(QtCore.Qt.gray)
            self.listWidgetA.addItem(listItemAInstance) 

            listItemBInstance=MyClassItem()
            listItemBInstance.setText('B'+'%04d'%i)

            if i%2: listItemBInstance.setBackgroundColor(QtCore.Qt.lightGray)
            self.listWidgetB.addItem(listItemBInstance) 

        myBoxLayout.addWidget(self.listWidgetA)      

        myBoxLayout.addWidget(self.listWidgetB)   
        self.connect(self.listWidgetA, QtCore.SIGNAL("dropped"), self.droppedOnA)
        self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.droppedOnB)


    def droppedOnA(self, arg):
        print '\n\t droppedOnA', arg.text

    def droppedOnB(self, arg):
        print '\n\t droppedOnB', arg.text


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

编辑#3

这是另一个尝试,这次使用 MIME 将放置的 Item 的对象传递给 ListWidget。不幸的是,cPickle 拒绝接受抛出

的二进制对象

TypeError: the sip.wrapper type cannot be instantiated or sub-classed

为了解决这个问题,我将每个对象名称转换为字符串,并将其与 self.listItems={} 字典一起用作检索列表项的二进制对象的键。这似乎运作良好。但是最后,当我几乎完成所有操作时,没有可见错误的 ListWidget 不会将删除的列表项添加到自身中……这很奇怪。

self.listWidgetB.addItem(droppedItemInstance)

.


from PyQt4 import QtGui, QtCore
import sys, os
import cPickle 

class MyClassItem(QtGui.QListWidgetItem):
    def __init__(self, parent=None):
        super(QtGui.QListWidgetItem, self).__init__(parent)       


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

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

        else:
            event.setDropAction(QtCore.Qt.MoveAction)
            super(ThumbListWidget, self).dropEvent(event)


    def mimeTypes(self):
        return ['bstream', 'text/xml']

    def mimeData(self, droppedItems):
        mimedata = QtCore.QMimeData()

        droppedItemsAsStrings=[]
        for each in droppedItems:            
            droppedItemsAsStrings.append( str(each) )

        bstream = cPickle.dumps(droppedItemsAsStrings)
        mimedata.setData('bstream', bstream)        
        return mimedata


    def dropMimeData(self, action, mimedata, row):

        if action == QtCore.Qt.IgnoreAction: return True  

        dropped=cPickle.loads(str(mimedata.data('bstream')))

        self.emit(QtCore.SIGNAL("dropped"), dropped)  

        return True


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)
        self.listWidgetB = ThumbListWidget(self)

        for i in range(7):
            listItemAInstance=MyClassItem()
            listItemAInstance.setText('A'+'%04d'%i)
            listItemAInstance.setBackgroundColor(QtCore.Qt.darkGray)   
            if i%2: listItemAInstance.setBackgroundColor(QtCore.Qt.gray)
            self.listWidgetA.addItem(listItemAInstance) 

            listItemBInstance=MyClassItem()
            listItemBInstance.setText('B'+'%04d'%i)

            if i%2: listItemBInstance.setBackgroundColor(QtCore.Qt.lightGray)
            self.listWidgetB.addItem(listItemBInstance) 

            self.listItems[str(listItemAInstance)]=listItemAInstance
            self.listItems[str(listItemBInstance)]=listItemBInstance

        myBoxLayout.addWidget(self.listWidgetA)      

        myBoxLayout.addWidget(self.listWidgetB)   
        self.connect(self.listWidgetA, QtCore.SIGNAL("dropped"), self.droppedOnA)
        self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.droppedOnB)


    def droppedOnA(self, droppedItemsAsStrings):
        print '\n\t droppedOnA()'
        for each in droppedItemsAsStrings:
            if each in self.listItems.keys():
                droppedItemInstance = self.listItems[each]
                print 'adding', droppedItemInstance.text()
                self.listWidgetA.addItem(droppedItemInstance) 


    def droppedOnB(self, droppedItemsAsStrings):
        print '\n\t droppedOnB()'
        for each in droppedItemsAsStrings:
            if each in self.listItems.keys():
                droppedItemInstance = self.listItems[each]
                self.listWidgetB.addItem(droppedItemInstance) 
                print 'adding', droppedItemInstance.text()


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

最佳答案

这是修改后的代码。它就像一个魅力!太棒了!

from PyQt4 import QtGui, QtCore
import sys, os

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

    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):
        print 'dropEvent', 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)
            super(ThumbListWidget, self).dropEvent(event)


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)
        for i in range(12): 
            QtGui.QListWidgetItem( 'Item '+str(i), self.listWidgetA )
        myBoxLayout.addWidget(self.listWidgetA)

        self.listWidgetB = ThumbListWidget(self)
        myBoxLayout.addWidget(self.listWidgetB)   

        self.connect(self.listWidgetA, QtCore.SIGNAL("dropped"), self.items_dropped)
        self.listWidgetA.currentItemChanged.connect(self.item_clicked)

        self.connect(self.listWidgetB, QtCore.SIGNAL("dropped"), self.items_dropped)
        self.listWidgetB.currentItemChanged.connect(self.item_clicked)

    def items_dropped(self, arg):
        print 'items_dropped', arg

    def item_clicked(self, arg):
        print arg

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

关于python - 如何从一个 QListWidget 拖放到另一个,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22543644/

相关文章:

Python/PyQT QString 不会插入到 MySQL 数据库中

python - 从带有富文本的 QLabel 中获取纯文本

qt - 我可以将对象附加到 PyQt 中的 QListWidgetItems 吗?

c++ - 文本更改时 QListWidget 可编辑项目信号

python - pyqt - 将 qt 设计器中的子小部件放置在父级附近

python - Pyqt5 根据自定义小部件中的事件刷新/更新 QListWidget?

python - 无法在 Flask 和 sqlalchemy 中多次导入数据库对象

python - 窄矩阵的 matplotlib 纵横比

python - Scrapy - 从 URL 获取文件大小和类型而不下载文件?

python - 合并数据框、删除列和设置索引