[PyQt] Editable reorderable (by drag and drop) QTreeView example

Hans-Peter Jansen hpj at urpla.net
Wed Oct 26 14:03:44 BST 2016


Hi PyQties,

after being unable to find a decent generic hierarchical reorderable drag
and drop example for QTreeView, I tried to transform the Editable Tree Model 
example code accordingly. 

--- editabletreemodel.py.orig	2015-07-17 13:39:33.000000000 +0200
+++ editabletreemodel.py	2016-10-26 00:24:51.857176297 +0200
@@ -44,7 +44,7 @@
 
 from PyQt5.QtCore import (QAbstractItemModel, QFile, QIODevice,
         QItemSelectionModel, QModelIndex, Qt)
-from PyQt5.QtWidgets import QApplication, QMainWindow
+from PyQt5.QtWidgets import QApplication, QMainWindow, QAbstractItemView
 
 import editabletreemodel_rc
 from ui_mainwindow import Ui_MainWindow
@@ -151,10 +151,12 @@ class TreeModel(QAbstractItemModel):
         return item.data(index.column())
 
     def flags(self, index):
-        if not index.isValid():
-            return 0
+        defaultFlags = Qt.ItemIsEditable | super(TreeModel, self).flags(index)
 
-        return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
+        if index.isValid():
+            return defaultFlags | Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled
+        else:
+            return defaultFlags | Qt.ItemIsDropEnabled
 
     def getItem(self, index):
         if index.isValid():
@@ -296,6 +298,9 @@ class TreeModel(QAbstractItemModel):
 
             number += 1
 
+    def supportedDropActions(self):
+        return Qt.MoveAction
+
 
 class MainWindow(QMainWindow, Ui_MainWindow):
     def __init__(self, parent=None):
@@ -311,6 +316,7 @@ class MainWindow(QMainWindow, Ui_MainWin
         file.close()
 
         self.view.setModel(model)
+        self.view.setDragDropMode(QAbstractItemView.InternalMove)
         for column in range(model.columnCount()):
             self.view.resizeColumnToContents(column)
 

In theory, this is all, what is needed to be able to reorder items in a 
QListView, is it?

While this change allows moving items, dropping them results in an empty row, 
and the entry isn't moved at all.

Any idea, what I'm missing here, before I dive into the source of 
Q{Standard,Abstract}ItemModel, that allows exactly this?

E.g.:

import sys
from PyQt5 import QtGui, QtCore, QtWidgets

class StandardItemModel(QtGui.QStandardItemModel):
    def __init__(self, parent = None):
        super(StandardItemModel, self).__init__(parent)

    def itemList(self, parent = QtCore.QModelIndex()):
        items = []
        for row in range(self.rowCount(parent)):
            idx = self.index(row, 0, parent)
            items.append(self.data(idx))
            if self.hasChildren(idx):
                items.append(self.itemList(idx))
        return items

    def populate(self):
        for row in range(0, 10):
            parentItem = self.invisibleRootItem()
            for col in range(0, 4):
                item = QtGui.QStandardItem("item (%s, %s)" % (row, col))
                parentItem.appendRow(item)
                parentItem = item


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

        self.model = StandardItemModel()
        self.model.populate()

        self.view = QtWidgets.QTreeView()
        self.view.setModel(self.model)
        self.view.setHeaderHidden(True)
        self.view.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)

        self.setCentralWidget(self.view)

def main():
    app = QtWidgets.QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()
    print(form.model.itemList())

if __name__ == '__main__':
    main()

TIA,
Pete


-------------- next part --------------
A non-text attachment was scrubbed...
Name: dnd-py.diff
Type: text/x-patch
Size: 1581 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20161026/9da1cdcb/attachment-0001.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: editabletreemodel.py
Type: text/x-python
Size: 14201 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20161026/9da1cdcb/attachment-0002.py>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: treeview.py
Type: text/x-python
Size: 1432 bytes
Desc: not available
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20161026/9da1cdcb/attachment-0003.py>


More information about the PyQt mailing list