Python 如何从一个QListWidget拖放到另一个
在同一个对话框窗口中有两个QListWidget。这两个系统都启用了DragDrop功能。如果我将一个文件拖放到两个ListWidges中的任何一个,程序会识别它并打印出所拖放文件的列表。但是除了拖放文件之外,我希望能够将列表小部件项从一个拖放到另一个。如果我拖动ListItems,则会触发拖放事件。但它无法识别哪些项目被丢到了小部件上。下面是示例代码。目标是将列表项从一个ListWidget拖放到另一个ListWidgetPython 如何从一个QListWidget拖放到另一个,python,pyqt4,qlistwidget,Python,Pyqt4,Qlistwidget,在同一个对话框窗口中有两个QListWidget。这两个系统都启用了DragDrop功能。如果我将一个文件拖放到两个ListWidges中的任何一个,程序会识别它并打印出所拖放文件的列表。但是除了拖放文件之外,我希望能够将列表小部件项从一个拖放到另一个。如果我拖动ListItems,则会触发拖放事件。但它无法识别哪些项目被丢到了小部件上。下面是示例代码。目标是将列表项从一个ListWidget拖放到另一个ListWidget import sys, os from PyQt4 import Qt
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()方法仍然不起作用
编辑#3 这是这次使用MIME将被删除项的对象传递给ListWidget的另一次尝试。不幸的是,cPickle拒绝接受抛出 TypeError:无法实例化或子分类sip.wrapper类型 为了解决这个问题,我将每个对象名转换为字符串,并将其与self.listItems={}dictionary一起用作检索列表项二进制对象的键。看起来效果不错。但在最后,当我几乎认为一切都已完成时,没有可见错误的ListWidget不会将删除的列表项添加到自身中。。。真奇怪 self.listWidgetB.addItem(droppedItemInstance)
假设您想要移动列表小部件项,您的子类应该如下所示(请注意,
setDragDropMode
和setSelectionMode
已被移动到\uuu init\uuuu
):
这是一个修改后的代码。它工作起来很有魅力!好极了
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 3风格的
super()
时,上面的代码对我来说不起作用
问题是继承的方法dragmovevent
和dragDropEvent
没有被子类中的新定义覆盖
因此,未调用event.setDropAction(QtCore.Qt.MoveAction)
,小部件行为默认为QtCore.Qt.CopyAction
我使用继承自qabstractemview
类的setDefaultDropAction()
方法解决了这个问题
以下是PyQt5和Python 3.7中的实现:
class NewDragDropWidget(QListWidget):
def __init__(self):
super().__init__()
self.setIconSize(QtCore.QSize(124, 124))
self.setDragDropMode(QAbstractItemView.DragDrop)
self.setDefaultDropAction(QtCore.Qt.MoveAction) # this was the magic line
self.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.setAcceptDrops(True)
让我试试!谢谢很好!谢谢你!显然,奇迹发生了,因为有以下几行:event.setDropAction(QtCore.Qt.MoveAction)和super(ThumbListWidget,self)。dropEvent(event)我用注释掉的这些行运行代码。如果删除这些行,将取消删除操作以及对listWidget的项目分配。然而,我不能理解它的语法。如果您能澄清那里发生了什么,我将不胜感激……第一行确保项目被移动,而不是复制(这是错误)。第二行调用
dropEvent
的基类实现。一个QListWidget
已经知道如何复制/移动它的项目,所以我们就让它做它自己的事情…PS:如果你注释掉所有的拖放方法,并转到MoveAction
,你将以同样的行为结束。只是因为您出于其他原因重写了这些方法,才需要这些额外的行。
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()))
self.emit(QtCore.SIGNAL("dropped"), links)
else:
event.setDropAction(QtCore.Qt.MoveAction)
super(ThumbListWidget, self).dropEvent(event)
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_())
class NewDragDropWidget(QListWidget):
def __init__(self):
super().__init__()
self.setIconSize(QtCore.QSize(124, 124))
self.setDragDropMode(QAbstractItemView.DragDrop)
self.setDefaultDropAction(QtCore.Qt.MoveAction) # this was the magic line
self.setSelectionMode(QAbstractItemView.ExtendedSelection)
self.setAcceptDrops(True)