canFetchMore() and fetchMore() are not working as expected

99封情书 提交于 2019-12-10 11:18:16

问题


I have problems implementing Qt tree model with lazy loading using canFetchMore() and fetchMore(). I have this code:

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

It is probably the shortest version (simplified, unoptimized, not general enough etc.) of the code which can replicate the problem. I want to display a tree of lists of ints. Note that in the example above I have two lists of ints, each containing 1000 ints. But for some unknown reason, only he first 300 ints are displayed when the node is expanded and after I scroll to the very bottom. I would expect that the items should be added as I am scrolling down. However they are only added when I collapse and expand again the node.

In other words, the nodes are being added only as a reaction to collapsing and expanding of the parent nodes, not as a reaction to scrolling to the bottom.

What is the problem? Have I overlooked anything?

UPDATE: I simplified the code even more, compared to the first version.

UPDATE2: To compare it with a model without hierarchy, which works as expected (fetching more data as user scrolls down), look at this code:

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

Does it mean I got something wrong with hierarchy?

来源:https://stackoverflow.com/questions/41684064/canfetchmore-and-fetchmore-are-not-working-as-expected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!