使用canFetchMore()
和fetchMore()
延迟加载实现Qt树模型时遇到问题。我有这段代码:
from PySide.QtCore import Qt, QAbstractItemModel, QModelIndex
from PySide.QtWidgets import QTreeView, QApplication
BATCH_SIZE = 100
class ObjectItem(object):
def __init__(self, parent, name, data, row):
self.parent = parent
self.name = name
self.data = data
self.row = row
self.hasChildren = False
self.canFetchMore = False
# ints have no children
if isinstance(data, int):
return
self.childCount = 0
self.childItems = []
if len(data) > 0:
self.canFetchMore = True
self.hasChildren = True
self.childCount = len(self.childItems)
if self.childCount > 0:
self.hasChildren = True
def fetchMore(self):
loadedCount = len(self.childItems)
totalCount = len(self.data)
remainder = totalCount - loadedCount
fetchCount = min(BATCH_SIZE, remainder)
for _ in range(fetchCount):
name = "[{}]".format(loadedCount)
value = self.data[loadedCount]
self.childItems.append(ObjectItem(self, name, value, loadedCount))
loadedCount += 1
self.canFetchMore = loadedCount < totalCount
return fetchCount
class MyTreeModel(QAbstractItemModel):
def __init__(self, data, parent=None):
super(MyTreeModel, self).__init__(parent)
self.rootItem = ObjectItem(None, "root", data, 0)
self.headerLabels = ["Name", "Type", "Value"]
def hasChildren(self, parent=QModelIndex()):
return parent.internalPointer().hasChildren if parent.isValid() else True
def rowCount(self, parent=QModelIndex()):
return parent.internalPointer().childCount if parent.isValid() else 1
def columnCount(self, parent=QModelIndex()):
return 3
def index(self, row, column, parent=QModelIndex()):
if not parent.isValid():
return self.createIndex(row, column, self.rootItem)
parentItem = parent.internalPointer()
return self.createIndex(row, column, parentItem.childItems[row])
def parent(self, index):
item = index.internalPointer()
if item == self.rootItem:
return QModelIndex()
parentItem = item.parent
return self.createIndex(parentItem.row, 0, parentItem)
def data(self, index, role):
item = index.internalPointer()
if role == Qt.DisplayRole:
if index.column() == 0:
return item.name
elif index.column() == 1:
return item.data.__class__.__name__
elif index.column() == 2:
return repr(item.data)
return None
def headerData(self, index, orientation, role):
if orientation == Qt.Horizontal and role == Qt.DisplayRole:
return self.headerLabels[index]
return None
def canFetchMore(self, parent=QModelIndex()):
if parent.isValid():
return parent.internalPointer().canFetchMore
else:
return False
def fetchMore(self, parent=QModelIndex()):
parentItem = parent.internalPointer()
firstIndex = parentItem.childCount
fetchedCount = parentItem.fetchMore()
lastIndex = firstIndex + fetchedCount - 1
self.beginInsertRows(parent, firstIndex, lastIndex)
parentItem.childCount = len(parentItem.childItems)
self.endInsertRows()
# test data
data = [list(range(1000)), list(range(1000))]
app = QApplication([])
view = QTreeView()
model = MyTreeModel(data)
view.setModel(model)
view.show()
app.exec_()
这可能是代码的最短版本(简化,未经优化,不够通用等),可以复制问题。我想显示list
个int
s的树。请注意,在上面的示例中,我有两个list
个int
s,每个int
s包含1000个int
s。但由于某些未知原因,当节点展开时以及滚动到最底部后,只有前300个from PySide.QtCore import Qt, QAbstractItemModel, QModelIndex
from PySide.QtGui import QApplication, QTreeView
BATCH_SIZE = 100
class LazyModel(QAbstractItemModel):
def __init__(self, totalCount, parent=None):
super(LazyModel, self).__init__(parent)
self.items = []
self.totalCount = totalCount
self.loadedCount = 0
def hasChildren(self, parent=QModelIndex()):
if not parent.isValid():
return True
else:
return False
def rowCount(self, parent=QModelIndex()):
return self.loadedCount
def columnCount(self, parent=QModelIndex()):
return 2
def index(self, row, column, parent=QModelIndex()):
return self.createIndex(row, column, None)
def parent(self, index):
return QModelIndex()
def data(self, index, role):
if role == Qt.DisplayRole:
if index.column() == 0:
return str(index.row())
else:
return str(self.items[index.row()])
return None
def canFetchMore(self, parent=QModelIndex()):
return self.loadedCount < self.totalCount
def fetchMore(self, parent=QModelIndex()):
remainder = self.totalCount - self.loadedCount
fetchCount = min(BATCH_SIZE, remainder)
for i in range(fetchCount):
self.items.append(len(self.items))
self.beginInsertRows(parent, self.loadedCount,
self.loadedCount + fetchCount - 1)
self.loadedCount += fetchCount
self.endInsertRows()
app = QApplication([])
view = QTreeView()
model = LazyModel(10000)
view.setModel(model)
view.show()
app.exec_()
被显示。我希望在我向下滚动时添加项目。但是,只有当我折叠并再次展开节点时才会添加它们。
换句话说,添加节点只是为了对父节点的折叠和扩展做出反应,而不是作为对滚动到底部的反应。
有什么问题?我忽略了什么吗?
更新:与第一个版本相比,我更加简化了代码。
UPDATE2:要将它与没有层次结构的模型进行比较,它按预期工作(当用户向下滚动时获取更多数据),请查看以下代码:
u
这是否意味着我的等级制度有问题?