저는 최근 PyQt를 사용하는 프로젝트에서 벽을 때렸습니다. QTreeView QAbstractItemModel 일반적으로 수천 개의 노드가 있습니다. 지금까지는 문제가 없었지만 많은 노드를 선택하는 것이 매우 느리다는 것을 깨달았습니다. 파고가 끝나면 QAbstractItemModel.parent()가 너무 자주 호출되는 것으로 나타났습니다.QTreeView에서 선택이 느린 이유는 무엇입니까?
#!/usr/bin/env python
import sys
import cProfile
import pstats
from PyQt4.QtCore import Qt, QAbstractItemModel, QVariant, QModelIndex
from PyQt4.QtGui import QApplication, QTreeView
# 200 root nodes with 10 subnodes each
class TreeNode(object):
def __init__(self, parent, row, text):
self.parent = parent
self.row = row
self.text = text
if parent is None: # root node, create subnodes
self.children = [TreeNode(self, i, unicode(i)) for i in range(10)]
else:
self.children = []
class TreeModel(QAbstractItemModel):
def __init__(self):
QAbstractItemModel.__init__(self)
self.nodes = [TreeNode(None, i, unicode(i)) for i in range(200)]
def index(self, row, column, parent):
if not self.nodes:
return QModelIndex()
if not parent.isValid():
return self.createIndex(row, column, self.nodes[row])
node = parent.internalPointer()
return self.createIndex(row, column, node.children[row])
def parent(self, index):
if not index.isValid():
return QModelIndex()
node = index.internalPointer()
if node.parent is None:
return QModelIndex()
else:
return self.createIndex(node.parent.row, 0, node.parent)
def columnCount(self, parent):
return 1
def rowCount(self, parent):
if not parent.isValid():
return len(self.nodes)
node = parent.internalPointer()
return len(node.children)
def data(self, index, role):
if not index.isValid():
return QVariant()
node = index.internalPointer()
if role == Qt.DisplayRole:
return QVariant(node.text)
return QVariant()
app = QApplication(sys.argv)
treemodel = TreeModel()
treeview = QTreeView()
treeview.setSelectionMode(QTreeView.ExtendedSelection)
treeview.setSelectionBehavior(QTreeView.SelectRows)
treeview.setModel(treemodel)
treeview.expandAll()
treeview.show()
cProfile.run('app.exec_()', 'profdata')
p = pstats.Stats('profdata')
p.sort_stats('time').print_stats()
그냥 코드를 실행, 문제를 재현하려면 (프로파일 않음) 및 (중 시프트 선택 또는 Cmd를-A를 통해) 트리 위젯의 모든 노드를 선택 : 나는 문제를 재현하기 위해 최소한의 코드를 만들었습니다. 당신이 응용 프로그램을 종료하면, 프로파일 링 통계 같은 표시됩니다 :
Fri May 8 20:04:26 2009 profdata
628377 function calls in 6.210 CPU seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
1 4.788 4.788 6.210 6.210 {built-in method exec_}
136585 0.861 0.000 1.182 0.000 /Users/hsoft/Desktop/slow_selection.py:34(parent)
142123 0.217 0.000 0.217 0.000 {built-in method createIndex}
17519 0.148 0.000 0.164 0.000 /Users/hsoft/Desktop/slow_selection.py:52(data)
162198 0.094 0.000 0.094 0.000 {built-in method isValid}
8000 0.055 0.000 0.076 0.000 /Users/hsoft/Desktop/slow_selection.py:26(index)
161357 0.047 0.000 0.047 0.000 {built-in method internalPointer}
94 0.000 0.000 0.000 0.000 /Users/hsoft/Desktop/slow_selection.py:46(rowCount)
404 0.000 0.000 0.000 0.000 /Users/hsoft/Desktop/slow_selection.py:43(columnCount)
94 0.000 0.000 0.000 0.000 {len}
1 0.000 0.000 6.210 6.210 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
이 데이터에 이상한 부분이라고 얼마나 자주 부모()이다 : 136k 번 2K 노드! 누구나 단서가 있습니까? 당신의 트리 뷰에 대한 setUniformRowHeights(true)
를 호출
힌트를 보내 주셔서 감사합니다.하지만 불행히도 도움이되지 않았습니다. 그것은 부모 호출의 수를 줄 였지만 단지 134k 호출까지 줄였습니다. Modeltest에 관해서는 재미 있지만, PyQt에서 타사 C++ 구성 요소를 가져 오는 방법을 알지 못합니다. 그러나 어쨌든이 모델이 맞았다는 생각이 듭니다. –