【问题标题】:Multiple drag and drop in PyQt4PyQt4中的多次拖放
【发布时间】:2010-08-11 13:04:47
【问题描述】:

我找不到使用 Qt/PyQt 拖放多个元素的示例; 在我的情况下,我需要从这个 QTableView 中拖动元素:

class DragTable(QTableView):
    def __init__(self, parent = None):
        super(DragTable, self).__init__(parent)
        self.setDragEnabled(True)

    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat("application/pubmedrecord"):
            event.setDropAction(Qt.MoveAction)
            event.accept()
        else:
            event.ignore()

    def startDrag(self, event):
        print type(event)
        index = self.indexAt(event.pos())
        if not index.isValid():
            return

        selected = index.row()
        bstream = cPickle.dumps(selected)
        mimeData = QMimeData()
        mimeData.setData("application/pubmedrecord", bstream)
        drag = QDrag(self)
        drag.setMimeData(mimeData)
        pixmap = QPixmap(":/drag.png")

        drag.setHotSpot(QPoint(pixmap.width()/3, pixmap.height()/3))
        drag.setPixmap(pixmap)
        result = drag.start(Qt.MoveAction)

    def mouseMoveEvent(self, event):
        self.startDrag(event)

到这个QLabel(我的dropzone):

class TagLabel(QLabel):
    def __init__(self, text, color, parent = None):
        super(TagLabel, self).__init__(parent)
        self.tagColor = color
        self.setText(text)
        self.setStyleSheet("QLabel { background-color: %s; font-size: 14pt; }" % self.tagColor)
        self.defaultStyle = self.styleSheet()
        self.setAlignment(Qt.AlignHCenter|Qt.AlignVCenter)
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat("application/pubmedrecord"):
            self.set_bg(True)
            event.accept()
        else:
            event.reject()

    def dragLeaveEvent(self, event):
        self.set_bg(False)
        event.accept()

    def dropEvent(self, event):
        self.set_bg(False)
        data = event.mimeData()
        bstream = data.retrieveData("application/pubmedrecord", QVariant.ByteArray)
        selected = pickle.loads(bstream.toByteArray())
        event.accept()
        self.emit(SIGNAL("dropAccepted(PyQt_PyObject)"), (selected, str(self.text()), str(self.tagColor)))

    def set_bg(self, active = False):
        if active:
            style = "QLabel {background: yellow; font-size: 14pt;}"
            self.setStyleSheet(style)
        else:
            self.setStyleSheet(self.defaultStyle)

有什么建议吗?谢谢!

【问题讨论】:

    标签: python drag-and-drop pyqt pyqt4


    【解决方案1】:

    这是一个完整的工作示例:

    from PyQt4 import QtCore, QtGui, Qt
    import cPickle
    import pickle
    

    您为什么使用cPicklepickle

    class DragTable(QtGui.QTableView):
        def __init__(self, parent = None):
            super(DragTable, self).__init__(parent)
            self.setDragEnabled(True)
            self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
    

    您可能希望在此处设置选择行为,因为我假设基于行的数据表示。你当然可以改变它。

        def dragEnterEvent(self, event):
            if event.mimeData().hasFormat("application/pubmedrecord"):
                event.setDropAction(Qt.MoveAction)
                event.accept()
            else:
                event.ignore()
    
        def startDrag(self, event):
    

    根据事件位置,您的代码在此处仅假定一个索引。对于QTableView,这是不必要的,因为它本身已经处理了鼠标单击。相反,最好还是像往常一样依靠 Qt 为您提供您实际需要的信息。在这里,我选择使用selectedIndexes()

            indices = self.selectedIndexes()
    

    Indices 现在是QModelIndex 实例的列表,我选择将其转换为一组行号。根据您的需要,也可以将这些转换为QPersistentModelIndexes 列表。

    这里可能会让您感到惊讶的是,无论选择行为如何,索引都包含表中所有 单元格 的索引,而不是所有行的索引。这就是为什么我选择使用set 而不是list

            selected = set()
            for index in indices:
                selected.add(index.row())
    

    假设你知道你在那里做什么,我没有改变其余的。

            bstream = cPickle.dumps(selected)
            mimeData = QtCore.QMimeData()
            mimeData.setData("application/pubmedrecord", bstream)
            drag = QtGui.QDrag(self)
            drag.setMimeData(mimeData)
            pixmap = QtGui.QPixmap(":/drag.png")
    
            drag.setHotSpot(QtCore.QPoint(pixmap.width()/3, pixmap.height()/3))
            drag.setPixmap(pixmap)
            result = drag.start(QtCore.Qt.MoveAction)
    
        def mouseMoveEvent(self, event):
            self.startDrag(event)
    
    
    class TagLabel(QtGui.QLabel):
        def __init__(self, text, color, parent = None):
            super(TagLabel, self).__init__(parent)
            self.tagColor = color
            self.setText(text)
            self.setStyleSheet("QLabel { background-color: %s; font-size: 14pt; }" % self.tagColor)
            self.defaultStyle = self.styleSheet()
            self.setAlignment(QtCore.Qt.AlignHCenter|QtCore.Qt.AlignVCenter)
            self.setAcceptDrops(True)
    
        def dragEnterEvent(self, event):
            if event.mimeData().hasFormat("application/pubmedrecord"):
                self.set_bg(True)
                event.accept()
            else:
                event.reject()
    
        def dragLeaveEvent(self, event):
            self.set_bg(False)
            event.accept()
    
        def dropEvent(self, event):
            self.set_bg(False)
            data = event.mimeData()
            bstream = data.retrieveData("application/pubmedrecord", QtCore.QVariant.ByteArray)
            selected = pickle.loads(bstream.toByteArray())
            event.accept()
            self.emit(QtCore.SIGNAL("dropAccepted(PyQt_PyObject)"), (selected, str(self.text()), str(self.tagColor)))
    

    除非您使用此信号与 C++ 代码交互,否则无需在此处添加信号参数,您也可以使用不带括号的 dropAccepted,PyQt4 会做正确的事情。

        def set_bg(self, active = False):
            if active:
                style = "QLabel {background: yellow; font-size: 14pt;}"
                self.setStyleSheet(style)
            else:
                self.setStyleSheet(self.defaultStyle)
    
    
    
    app = QtGui.QApplication([])
    
    l = TagLabel("bla bla bla bla bla bla bla", "red")
    l.show()
    
    m = QtGui.QStandardItemModel()
    for _ in xrange(4):
        m.appendRow([QtGui.QStandardItem(x) for x in ["aap", "noot", "mies"]])
    
    t = DragTable()
    t.setModel(m)
    t.show()
    
    def h(o):
        print "signal handled", o
    l.connect(l, QtCore.SIGNAL("dropAccepted(PyQt_PyObject)"), h)
    
    app.exec_()
    

    【讨论】:

    • 很好的解释,我不能要求更多:) 谢谢!
    • 为什么这不能用 QListWidget 代替 QLabel 工作?
    • 好的,它可以工作,但前提是你在 QListWidget 上使用 setDragDropMode(4)。
    猜你喜欢
    • 2013-01-01
    • 1970-01-01
    • 2012-01-14
    • 1970-01-01
    • 2014-06-21
    • 2011-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多