使用PyQt实现带拖放支持的QTreeView

12

我希望在PyQt4中创建一个QTreeView,并能够通过拖放操作重新组织它的结构。

我已经实现了自己的模型(QAbstractItemModel)来为QTreeView显示数据。现在我想为树节点添加拖放支持,以便能够将一个节点从一个父节点移动到另一个父节点,进行拖放复制等操作,但我找不到任何完整的教程来实现这个功能。我找到了一些针对QTreeWidget的教程和提示,但没有针对具有自定义模型的QTreeView的教程。有人能告诉我去哪里看吗?

谢谢。

1个回答

19

您可以通过将QtGui.QAbstractItemView.InternalMove设置为树形视图控件的dragDropMode属性来启用树形视图项的拖放支持。还可以在此处查看文档 使用带项目视图的拖放。以下是启用了其项的内部拖放的树视图的小示例。

import sys
from PyQt4 import QtGui, QtCore

class MainForm(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)

        self.model = QtGui.QStandardItemModel()

        for k in range(0, 4):
            parentItem = self.model.invisibleRootItem()
            for i in range(0, 4):
                item = QtGui.QStandardItem(QtCore.QString("item %0 %1").arg(k).arg(i))
                parentItem.appendRow(item)
                parentItem = item

        self.view = QtGui.QTreeView()
        self.view.setModel(self.model)
        self.view.setDragDropMode(QtGui.QAbstractItemView.InternalMove)

        self.setCentralWidget(self.view)

def main():
    app = QtGui.QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()

if __name__ == '__main__':
    main()

编辑0:带有拖放支持的TreeView +抽象模型

import sys
from PyQt4 import QtGui, QtCore

class TreeModel(QtCore.QAbstractItemModel):
    def __init__(self):
        QtCore.QAbstractItemModel.__init__(self)
        self.nodes = ['node0', 'node1', 'node2']

    def index(self, row, column, parent):
        return self.createIndex(row, column, self.nodes[row])

    def parent(self, index):
        return QtCore.QModelIndex()

    def rowCount(self, index):
        if index.internalPointer() in self.nodes:
            return 0
        return len(self.nodes)

    def columnCount(self, index):
        return 1

    def data(self, index, role):
        if role == 0: 
            return index.internalPointer()
        else:
            return None

    def supportedDropActions(self): 
        return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction         

    def flags(self, index):
        if not index.isValid():
            return QtCore.Qt.ItemIsEnabled
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | \
               QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled        

    def mimeTypes(self):
        return ['text/xml']

    def mimeData(self, indexes):
        mimedata = QtCore.QMimeData()
        mimedata.setData('text/xml', 'mimeData')
        return mimedata

    def dropMimeData(self, data, action, row, column, parent):
        print 'dropMimeData %s %s %s %s' % (data.data('text/xml'), action, row, parent) 
        return True


class MainForm(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)

        self.treeModel = TreeModel()

        self.view = QtGui.QTreeView()
        self.view.setModel(self.treeModel)
        self.view.setDragDropMode(QtGui.QAbstractItemView.InternalMove)

        self.setCentralWidget(self.view)

def main():
    app = QtGui.QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()

if __name__ == '__main__':
    main()

希望这能有所帮助,敬礼


谢谢您的回答。但它并没有解决我的问题。我知道使用QStandardItemModel + QStandardItem可以正常工作。但我需要使用CUSTOM模型,纯子类从QAbstractItemModel继承而来。我认为我需要在模型中实现一些方法或使用一些专门的对象来处理树形项目。现在,即使设置了拖放指示器的显示,拖动也不会显示甚至放置指示器...显然,我只是忽略了某些东西。 - Ondrej Vencovsky
我还有一个评论。如果您以PyQt标准示例中的“simpletreemodel”为例:如何为其添加拖放支持?如果我只是在视图中添加setAcceptsDrop(True)、setDragEnabled(True)、setDragDropMode(view.InternalMove),并在模型中添加ItemIsDragEnabled | ItemIsDropEnabled标志,这仅仅是不足以具备拖放功能的。 - Ondrej Vencovsky
从来没有看到过这方面的标准示例;但请记住,QT是开源的,所以您可以随时查看QStandardItemModel内部发生了什么,它是QAbstractItemModel的后代并支持拖放。我已经在我的帖子中编辑了一个简单的抽象模型示例,它应该支持拖放。 - serge_gubenko
1
是的,现在它可以工作了!你不知道我有多想感谢你。真的非常感谢。 - Ondrej Vencovsky
我发现在 python3 中的 PyQt 中不存在 QString。我读了这篇文章,它为我解决了这个问题:http://inputvalidation.blogspot.com/2010/10/python3-pyqt4-and-missing-qstring.html - REA_ANDREW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接