简体   繁体   English

如何从ListWidget拖放到ComboBox

[英]How to Drag and Drop from ListWidget onto ComboBox

The goal is to be able to drag-and-drop ListWidget items onto the comboBox. 目的是能够将ListWidget项拖放到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? 理想情况下,我们希望避免阅读listWidget的.currentItem()或.selectedItems()等技巧。

在此处输入图片说明

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

The "proper" way to do this would be to unpack the mimedata using a QDataStream . 执行此操作的“正确”方法是使用QDataStream解压缩mimedata。 However, this would seem to require the use of a QMap , which is not available in PyQt. 但是,这似乎需要使用QMap ,在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 . 另外,如果要防止添加重复项,请使用setDuplicatesEnabled And if you want to alter how the items are added, use setInsertPolicy . 如果要更改添加项目的方式,请使用setInsertPolicy

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM