Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QAbstractItemModel index() and parent() methods

It is required to implement QAbstractItemModel.parent() method or else get this nasty error:

NotImplementedError: QAbstractItemModel.parent() is abstract and must be overridden

Aside from .parent() the index() method also needs to be overridden or face:

NotImplementedError: QAbstractItemModel.index() is abstract and must be overridden

QUESTION: What are the purpose of both methods and what is the difference in the way they work?

EDITED LATER:

Example of .parent() method:

def getNodeFromIndex(self, index):    
    if index.isValid():
        node = index.internalPointer()
        if node:
            return node            
    return self.items


def parent(self, index):
    node = self.getNodeFromIndex(index)
    parentNode = node.getParent()
    if parentNode == self.items:
        return QtCore.QModelIndex()
    return self.createIndex(parentNode.row(), 0, parentNode)

Example on .index() method:

def index(self, row, column, parentIndex):
    parentNode = self.getNodeFromIndex(parentIndex)
    childNode = parentNode.getChildren(row)
    if childNode:            
        newIndex=self.createIndex(row, column, childNode)
        return newIndex
    else:
        return QtCore.QModelIndex()

From endless testing I do see that .parent() method is called only on top level QTableView items. While .index() is called for all the items: top-level, second-level children items, third-level grand-children items and etc. I also do see that both return QModelIndex with row, column and data variable "linked" to it. It looks like the QModelIndexes returned by both methods should be in sync.

The .parent() returns parent of model item with given index. If item has no parent, an invalid QModelIndex is returned. A common convention used in models that expose tree data structures is that only items in first column have children. For that case, when reimplementing this function in a subclass the column of the returned QModelIndex would be 0. When reimplementing this function in a subclass, be careful to avoid calling QModelIndex member functions, such as QModelIndex::parent(), since indexes belonging to your model will simply call your implementation leading to infinite recursion.

The .index() returns the index of the item in the model specified by the given row, column and parent index. When reimplementing this function in a subclass, call createIndex() to generate model indexes that other components can use to refer to items in your model.

It is worth to mention that both methods use self.createIndex(row, column, dataVariable) method. So they both do the same thing: they create QModelIndexes. I just don't understand why we need two methods to do the same thing! And it is hard to debug it since it seems they run in infinite loop....

like image 671
alphanumeric Avatar asked Jan 10 '15 02:01

alphanumeric


1 Answers

These methods are defined abstract to enforce the user to implement them when subclassing. Your model would not work without implementing them that's because they are necessary to define the structure of your model.

Usually when you want to create a hierarchical model you should implement index() and parent() methods. For table and list models, in many cases it's enough to subclass QAbstractListModel and QAbstractTableModel which have their default implementations of the two methods.

In simple words QAbstractItemModel.parent() returns the parent QModelIndex from a child and QAbstractItemModel.index() is called whenever the model or the view needs to create a QModelIndex for a particular child item (or a top-level item if parent is an invalid QModelIndex).

like image 64
Nejat Avatar answered Nov 14 '22 03:11

Nejat