PyQt项目视图自定义拖放

时间:2019-04-18 05:23:11

标签: python pyqt drag-and-drop pyqt4

我正在研究QTableView中的自定义拖放实现。当我将一个单元格拖放到另一个单元格上时,我想根据所拖动的内容和放置的位置手动更改模型中的某些数据。我怎样才能做到这一点?我一直在阅读所有Qt文档,但完全迷失了方向,尤其是通过拖放操作,似乎C ++到PyQt的转换不太直观。

基本上我需要的是放下它们时,我想知道最初拖动了哪些单元格以及将它们放到了哪里。我困惑的地方似乎在于QMimeData。从我可以知道什么时候开始拖动开始,拖动事件接收到正确的MIME数据,但是我不知道如何在PyQt中使用它(过去可以使用文本和url进行这种操作,但是我会丢失有关项目视图的信息)。我还需要知道我要去的地方。我想我可以做一个“游标pos处的项目”,但我假设该数据已经存在于drop事件中,我只需要弄清楚如何查询它即可。

这是一个简单的例子:

import sys
from PyQt4 import QtGui, QtCore


class TableView(QtGui.QTableView):
     def __init__(self, parent=None):
         QtGui.QTreeWidget.__init__(self, parent)
         self.setDragEnabled(True)
         self.setDropIndicatorShow(True)
         self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
         self.setDragDropOverwriteMode(False)
         self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)

     def dragEnterEvent(self, event):
        event.accept()

    def dropEvent(self, event):
        # I want to do cool things with the dragged cells, and I need to know where they dropped!
        print(event.mimeData().formats()) # this tells me that I shuld get some sort of "qabstractitemmodeldatalist". Sounds promising...
        print(event.mimeData().data("application/x-qabstractitemmodeldatalist")) # this gives me an interesting looking QByteArray but I have no idea what to do with it...
        event.accept()

class Dialog(QtGui.QDialog):
    def __init__(self):
        super(Dialog, self).__init__()

        model = QtGui.QStandardItemModel(self)
        model.insertRow(0, QtGui.QStandardItem("C"))
        model.insertRow(0, QtGui.QStandardItem("B"))
        model.insertRow(0, QtGui.QStandardItem("A"))

        table = TableView(self)
        table.setModel(model)

app = QtGui.QApplication(sys.argv)
ex = Dialog()
ex.show()
sys.exit(app.exec_())

1 个答案:

答案 0 :(得分:1)

由于mimeData没有该信息,因此您无法知道将其拖动到何处,但可以将数据拖动到该位置,为此,我们创建了一个临时模型,在该模型中,我们将建立mimeData来模拟拖动的相同行为。要获取放置在哪里,必须将与事件一起出现的位置与indexAt()一起使用,从而获得QModelIndex:

import sys
from PyQt4 import QtGui, QtCore


class TableView(QtGui.QTableView):
    def __init__(self, parent=None):
        QtGui.QTreeWidget.__init__(self, parent)
        self.setDragEnabled(True)
        self.setDropIndicatorShown(True)
        self.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
        self.setDragDropOverwriteMode(False)
        self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)

    def dragEnterEvent(self, event):
        event.accept()

    def dropEvent(self, event):
        if self.viewport().rect().contains(event.pos()):
            fake_model = QtGui.QStandardItemModel()
            fake_model.dropMimeData(
                event.mimeData(), event.dropAction(), 0, 0, QtCore.QModelIndex()
            )
            print("from:")
            for r in range(fake_model.rowCount()):
                for c in range(fake_model.columnCount()):
                    ix = fake_model.index(r, c)
                    print(ix.data())
            to_index = self.indexAt(event.pos())
            if to_index.isValid():
                print("to:", to_index.data())
        super(TableView, self).dropEvent(event)


class Dialog(QtGui.QDialog):
    def __init__(self):
        super(Dialog, self).__init__()

        model = QtGui.QStandardItemModel(self)
        for letter in "ABC":
            model.appendRow(QtGui.QStandardItem(letter))

        table = TableView()
        table.setModel(model)

        lay = QtGui.QVBoxLayout(self)
        lay.addWidget(table)


if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    ex = Dialog()
    ex.show()
    sys.exit(app.exec_())