问题
The goal is to be able to drag-and-drop ListWidget items onto the comboBox. The dropped items should be added to the combobox. Ideally we want to avoid any tricks with reading listWidget's .currentItem() or .selectedItems() and etc... Ideas?
from PyQt4 import QtGui, QtCore
import sys, os
class MyClass(object):
def __init__(self):
super(MyClass, self).__init__()
self.name=None
def setName(self, arg):
self.name=arg
def getName(self):
return self.name
class DropableComboBox(QtGui.QComboBox):
def __init__(self):
self.model_mime_type = 'application/x-qabstractitemmodeldatalist'
super(DropableComboBox, self).__init__()
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
if event.mimeData().hasFormat(self.model_mime_type) or event.mimeData().hasFormat('text/plain'):
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:
super(DropableComboBox, self).dropEvent(event)
self.emit(QtCore.SIGNAL("dropped"))
class Dialog_01(QtGui.QMainWindow):
def __init__(self):
super(QtGui.QMainWindow,self).__init__()
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.listWidget = QtGui.QListWidget()
self.listWidget.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
self.listWidget.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self.listWidget.currentItemChanged.connect(self.item_clicked)
for i in range(3):
my_item=QtGui.QListWidgetItem()
name='ListWidget Item '+str(i)
my_item.setText(name)
self.listWidget.addItem(my_item)
myObject=MyClass()
myObject.setName(name)
my_item.setData(QtCore.Qt.UserRole, myObject)
myBoxLayout.addWidget(self.listWidget)
self.ComboBox = DropableComboBox()
for i in range(3):
self.ComboBox.addItem("Combobox Item " + str(i))
self.ComboBox.currentIndexChanged.connect(self.combobox_selected)
self.connect(self.ComboBox, QtCore.SIGNAL("dropped"), self.droppedOnCombobox)
myBoxLayout.addWidget(self.ComboBox)
def item_clicked(self, arg=None):
print arg.data(QtCore.Qt.UserRole).toPyObject().getName()
def combobox_selected(self, index):
myObject=self.ComboBox.itemData(index).toPyObject()
if hasattr(myObject, 'getName'): print myObject.getName()
def droppedOnCombobox(self):
print "Drop!"
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
dialog_1 = Dialog_01()
dialog_1.show()
dialog_1.resize(480,320)
sys.exit(app.exec_())
回答1:
The "proper" way to do this would be to unpack the mimedata using a QDataStream
. However, this would seem to require the use of a QMap
, which is not available in PyQt. So instead, it can be done in a slightly hacky (or should that be "tricky"?) way by getting a proxy model to the dirty work for us:
class DropableComboBox(QtGui.QComboBox):
def __init__(self):
super(DropableComboBox, self).__init__()
self.model_mime_type = 'application/x-qabstractitemmodeldatalist'
self.setAcceptDrops(True)
self._proxymodel = QtGui.QStandardItemModel(self)
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)
elif event.mimeData().hasFormat(self.model_mime_type):
self._proxymodel.setRowCount(0)
self._proxymodel.dropMimeData(
event.mimeData(), QtCore.Qt.CopyAction,
0, 0, QtCore.QModelIndex())
for index in range(self._proxymodel.rowCount()):
item = self._proxymodel.item(index, 0)
self.addItem(item.text())
# no point calling the base-class dropEvent here,
# because it's a NO-OP in QComboBox
self.emit(QtCore.SIGNAL("dropped"))
NB:
This will copy the items from the list-widget, rather than moving them (which you didn't ask for). Also, if you want to prevent duplicates being added, use setDuplicatesEnabled. And if you want to alter how the items are added, use setInsertPolicy.
来源:https://stackoverflow.com/questions/22774168/how-to-drag-and-drop-from-listwidget-onto-combobox