canFetchMore() и fetchMore() не работают должным образом

У меня проблемы с реализацией модели дерева Qt с ленивой загрузкой с использованием canFetchMore() и fetchMore(). У меня есть этот код:

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_()

Вероятно, это самая короткая версия (упрощенная, неоптимизированная, недостаточно общая и т. д.) кода, который может воспроизвести проблему. Я хочу отобразить дерево lists из ints. Обратите внимание, что в приведенном выше примере у меня есть два lists из ints, каждый из которых содержит 1000 ints. Но по какой-то неизвестной причине отображаются только первые 300 int при расширении узла и после прокрутки до самого низа. Я ожидаю, что элементы должны добавляться по мере прокрутки вниз. Однако они добавляются только тогда, когда я сворачиваю и снова расширяю узел.

Другими словами, узлы добавляются только как реакция на свертывание и расширение родительских узлов, а не как реакция на прокрутку вниз.

В чем проблема? Я ничего не упустил из виду?

ОБНОВЛЕНИЕ: я еще больше упростил код по сравнению с первой версией.

ОБНОВЛЕНИЕ 2: чтобы сравнить его с моделью без иерархии, которая работает, как и ожидалось (извлечение дополнительных данных по мере прокрутки пользователя), посмотрите на этот код:

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_()

Значит ли это, что у меня что-то не так с иерархией?


person V.K.    schedule 16.01.2017    source источник
comment
У меня точно такая же проблема. Вы нашли решение после вашего поста?   -  person cytrinox    schedule 20.03.2017
comment
Об этой ошибке уже сообщалось на странице bugreports.qt.io/browse/QTBUG-48725.   -  person cytrinox    schedule 20.03.2017
comment
Спасибо за ссылку на тикет об ошибках. До сих пор я не нашел ни удовлетворительного решения, ни обходного пути для этой проблемы.   -  person V.K.    schedule 20.03.2017