【问题标题】:PyQt item view custom drag and dropPyQt项目视图自定义拖放
【发布时间】:2019-04-18 05:23:10
【问题描述】:

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

基本上我需要的是当我放下时,我想知道最初拖动了哪些单元格,以及它们被放置在哪里。我的困惑似乎在于 QMimeData。据我所知,拖动开始时,拖动事件接收到正确的 MIME 数据,但我不知道如何在 PyQt 中获取它(过去能够用文本和 url 做这种事情,但我当涉及到项目视图时,我迷路了)。我还需要知道我要去哪里。我想我可以做一个“光标位置的项目”,但我假设这个数据已经存在于 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_())

【问题讨论】:

    标签: python pyqt drag-and-drop pyqt4


    【解决方案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_())
    

    【讨论】:

    • 谢谢,我从没想过要使用虚拟模型!
    • 你知道,也许 mimeData 没有拖动的单元格,但我刚刚发现我可以通过在 dragEnterEvent 中存储 self.selectedIndexes() 来捕获它们。
    • @Spencer 你说的是对的,mimetypes是一种传输数据的协议,在“application/x-qabstractitemmodeldatalist”的情况下只传输角色的信息。您的方法仅在拖放是同一视图时才有效。如果您希望另一个视图传递该信息,您应该在 mimedata 开始拖动时添加更多数据。此外,并非所有视图或 mimedata 源中都存在行和列的概念。
    • 有道理。幸运的是,在这种情况下,我知道它会在同一个视图中,所以我很容易!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-13
    • 1970-01-01
    • 2012-12-22
    • 1970-01-01
    相关资源
    最近更新 更多