Python PyQt4中的多个拖放操作

Python PyQt4中的多个拖放操作,python,drag-and-drop,pyqt,pyqt4,Python,Drag And Drop,Pyqt,Pyqt4,我找不到使用Qt/PyQt拖放多个元素的示例; 在本例中,我需要从该QTableView中拖动元素: class DragTable(QTableView): def __init__(self, parent = None): super(DragTable, self).__init__(parent) self.setDragEnabled(True) def dragEnterEvent(self, event): if

我找不到使用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 My 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)

有什么建议吗?谢谢大家!

下面是一个完整的工作示例:

from PyQt4 import QtCore, QtGui, Qt
import cPickle
import pickle
你为什么既用泡菜又用cPickle

您可能希望在这里设置选择行为,因为我假设的是基于行的数据表示。你当然可以改变这一点

    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为您提供实际需要的信息。在这里,我选择使用selectedIndex

索引现在是QModelIndex实例的列表,我选择将其转换为一组行号。根据您的需要,还可以将它们转换为QPersistentModelIndex列表

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

我没动其余的,假设你知道你在那里做什么

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

下面是一个完整的工作示例:

from PyQt4 import QtCore, QtGui, Qt
import cPickle
import pickle
你为什么既用泡菜又用cPickle

您可能希望在这里设置选择行为,因为我假设的是基于行的数据表示。你当然可以改变这一点

    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为您提供实际需要的信息。在这里,我选择使用selectedIndex

索引现在是QModelIndex实例的列表,我选择将其转换为一组行号。根据您的需要,还可以将它们转换为QPersistentModelIndex列表

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

我没动其余的,假设你知道你在那里做什么

        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上使用setDragDropMode4。很好的解释,我不能要求更多:谢谢!为什么这不适用于QListWidget而不是QLabel?好的,它可以工作,但只有在QListWidget上使用setDragDropMode4时才能工作。