从QModelIndex获取数据导致无限循环

1 投票
2 回答
770 浏览
提问于 2025-04-17 08:59

我在使用一个类时遇到了一些问题,这个类实现了 __getitem____setitem__ 这两个功能。

这个类的实例是 QAbstractListModel 的数据后端。当我在模型的 data(index) 方法中返回这些实例时,只有在 role==Qt.UserRole 的情况下,才能从模型外部访问这些对象。

我想要这样做的一个场景是,当用户在使用我模型的 QListView 中点击任何项目时。问题是,一旦我尝试从用户点击的索引中获取数据,我的程序就会在 __getattr__ 中进入一个无尽的循环。

下面是一个完整的代码片段,可以直接复制粘贴,这段代码会重现我所描述的行为。程序会在 testfuncindex.data(Qt.UserRole) 这一行陷入循环。

我是不是漏掉了什么,还是我在 PySide 中遇到了一个bug呢?

#!/usr/bin/python

from PySide.QtCore import QAbstractListModel, Qt, QObject
from PySide.QtGui import QApplication, QListView

import sys

###############################################################################

class TestObject(QObject):
    def __init__(self, parent=None):
        """Creates new instance of TestObject.
        @param parent Qt parent."""
        super(TestObject, self).__init__(parent)
        self._data = {}

    def __getitem__(self, key):
        """Gets an item from self._data"""
        if key in self._data.keys():
            return self._data[key]

    def __setitem__(self, key, value):
        """Sets the value for key."""
        self._data[key] = value

###############################################################################

class TestModel(QAbstractListModel):
    def __init__(self, parent=None):
        """Creates a new instance of TestModel.
        @param parent Qt parent."""
        super(TestModel, self).__init__(parent)
        self._objects = []
        for i in range(5):
            obj = TestObject(self)
            obj[i] = str(i)
            self._objects.append(obj)

    def rowCount(self, parent):
        """Returns the amount of datasets."""
        return len(self._objects)

    def columnCount(self):
        """Returns the amount of columns, which is 1."""
        return 1

    def data(self, index, role=Qt.DisplayRole):
        """Returns the data for the given model index"""
        if index.isValid():
            obj = self._objects[index.row()]
            if role == Qt.DisplayRole:
                return str(obj)
            elif role == Qt.UserRole:
                return obj
        return None

###############################################################################

def testfunc(index):
    """Does something with index."""
    print "getting..."
    index.data(Qt.UserRole)
    print "never getting here :/"

###############################################################################

if __name__ == "__main__":
    app = QApplication(sys.argv)
    view = QListView()
    view.setModel(TestModel())
    view.clicked.connect(testfunc)
    view.show()
    app.exec_()

2 个回答

0

看起来PySide在尝试遍历你的对象(具体原因不太清楚)。正如评论中所说的,你需要在__getitem__这个方法里抛出一个IndexError,这样才能在PySide内部停止这个遍历。

关于__getitem__和遍历对象的信息可以查看这里:https://stackoverflow.com/a/926645/812662

0

__getitem__ 这个方法在遇到无效的键时需要抛出一个 IndexError() 错误。

撰写回答