Cómo arrastrar y soltar desde ListWidget en ComboBox

El objective es poder arrastrar y soltar los elementos de ListWidget en el comboBox. Los elementos caídos deben agregarse al cuadro combinado. Idealmente, queremos evitar cualquier truco con la lectura de listWidget’s .currentItem () o .selectedItems () y etc … ¿Ideas?

introduzca la descripción de la imagen aquí

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

La forma “correcta” de hacer esto sería desempaquetar el mimedata usando un QDataStream . Sin embargo, esto parece requerir el uso de un QMap , que no está disponible en PyQt. Entonces, en lugar de eso, se puede hacer de una manera un poco pirateada (¿o debería ser “complicada”?) Al obtener un modelo de proxy para el trabajo sucio para nosotros:

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

NÓTESE BIEN:

Esto copiará los elementos de la lista-widget, en lugar de moverlos (lo que no solicitó). Además, si desea evitar que se agreguen duplicados, use setDuplicatesEnabled . Y si desea modificar la forma en que se agregan los elementos, use setInsertPolicy .