How to Drag and Drop from ListWidget onto ComboBox

随声附和 提交于 2019-12-10 10:48:50

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!