Hi everyone,

I've got a QTreeView with a custom model which has to handle several items (say 1 million). I've set the setUniformRowHeights property to True, so when the tree is set up the scrolling is very fluid. The problem arises when I try to change the ordering of the items.
The following code illustrates the situation I have to deal with:

Qt Code:
  1. from PyQt4.QtCore import *
  2. from PyQt4.QtGui import *
  3. from random import shuffle
  4. from time import clock
  5.  
  6. class TreeItem(object) :
  7. def __init__(self, data, parent=None) :
  8. self.parentItem = parent
  9. self.itemData = data
  10. self.childItems = []
  11.  
  12. def appendChild(self, item) :
  13. self.childItems.append(item)
  14.  
  15. def child(self, row) :
  16. return self.childItems[row]
  17.  
  18. def childCount(self) :
  19. return len(self.childItems)
  20.  
  21. def columnCount(self) :
  22. return len(self.itemData)
  23.  
  24. def data(self, column) :
  25. try :
  26. return self.itemData[column]
  27. except IndexError :
  28. return None
  29.  
  30. def parent(self) :
  31. return self.parentItem
  32.  
  33. def row(self) :
  34. if self.parentItem :
  35. return self.parentItem.childItems.index(self)
  36. return 0
  37.  
  38.  
  39. class TreeModel(QAbstractItemModel) :
  40. def __init__(self, ) :
  41. QAbstractItemModel.__init__(self)
  42.  
  43. self.root = TreeItem(("root",))
  44. self.fld = TreeItem(("Items",), self.root)
  45. self.root.appendChild(self.fld)
  46.  
  47. self.row_id = []
  48. for j in xrange(1000000) :
  49. self.row_id.append(j)
  50. self.fld.appendChild(TreeItem(("Item"+str(j+1),), self.fld))
  51. print "Done"
  52.  
  53. def _ItemFromIndex(self, index) :
  54. if not index.isValid() :
  55. return self.root
  56. item = index.internalPointer()
  57. if item == self.fld :
  58. return item
  59. fld_index = self.createIndex(0, 0, self.fld)
  60. return self.index(self.row_id[index.row()], 0, fld_index).internalPointer()
  61.  
  62. def columnCount(self, parent) :
  63. return 1
  64.  
  65. def data(self, index, role) :
  66. item = self._ItemFromIndex(index)
  67. if role == Qt.DisplayRole :
  68. return item.data(0)
  69.  
  70. def flags(self, flag) :
  71. return (Qt.ItemIsEnabled|Qt.ItemIsUserCheckable|Qt.ItemIsSelectable)
  72.  
  73. def hasChildren(self, parent=QModelIndex()) :
  74. if parent.column() > 0 :
  75. return False
  76. item = self.root if not parent.isValid() else parent.internalPointer()
  77. return item.childCount() != 0
  78.  
  79. def index(self, row, column, parent) :
  80. if not self.hasIndex(row, column, parent) :
  81. return QModelIndex()
  82.  
  83. parent = self.root if not parent.isValid() else parent.internalPointer()
  84. child = parent.child(row)
  85. return self.createIndex(row, column, child) if child else QModelIndex()
  86.  
  87. def parent(self, index):
  88. if not index.isValid() :
  89. return QModelIndex()
  90.  
  91. child = index.internalPointer()
  92. parent = child.parent()
  93.  
  94. if parent == self.root :
  95. return QModelIndex()
  96.  
  97. return self.createIndex(parent.row(), 0, parent)
  98.  
  99. def rowCount(self, parent=QModelIndex()) :
  100. if parent.column() > 0 :
  101. return 0
  102. item = self.root if not parent.isValid() else parent.internalPointer()
  103. return item.childCount()
  104.  
  105.  
  106. class Tree(QTreeView) :
  107. def __init__(self, parent, model) :
  108. QTreeView.__init__(self, parent)
  109. self.setHeaderHidden(True)
  110. self.setContextMenuPolicy(Qt.CustomContextMenu)
  111. self.setUniformRowHeights(True)
  112. self.setModel(model)
  113. self.expand(self.model().index(0, 0, QModelIndex()))
  114.  
  115. def Shuffle(self) :
  116. t1 = clock()
  117. shuffle(self.model().row_id)
  118. self.model().reset()
  119. self.expand(self.model().index(0, 0, QModelIndex()))
  120. print "Shuffle time:", clock()-t1
  121.  
  122. class Frame(QWidget) :
  123. def __init__(self, parent, model=None) :
  124. super(QWidget, self).__init__(parent)
  125.  
  126. self.tree = Tree(self, TreeModel())
  127. self.shuffle_btn = QPushButton("Shuffle")
  128. self.shuffle_btn.clicked.connect(self.tree.Shuffle)
  129.  
  130. vbox = QVBoxLayout()
  131. vbox.setContentsMargins(0, 0, 0, 0)
  132. vbox.addWidget(self.tree)
  133. vbox.addWidget(self.shuffle_btn)
  134. self.setLayout(vbox)
  135.  
  136. if __name__ == "__main__" :
  137. import sys
  138. a = QApplication(sys.argv)
  139.  
  140. dia = Frame(None)
  141. dia.resize(400, 600)
  142. dia.show()
  143. a.exec_()
To copy to clipboard, switch view to plain text mode 

I use the row_id list to map the items to be shown at a given index; I do this in order to use my own C-written sorting function to order the items. Now if you push the “Shuffle” button (which simulates the sorting) you can see that even if the execution time is fast (0.6 sec on my pc), the tree requires several seconds to be updated.
Can anyone point me out what I am doing wrong? Thanks in advance!