我正在研究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_())
答案 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_())