同一个对话窗口中有两个 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/