CopperSpice API  1.9.1
Other Model/View Topics

Parents and Children

Since the structure exposed to views is determined by the underlying data structure in the model, it is up to each model to create its own model indexes by implementing the following methods.

Both of these methods call the createIndex() method to generate indexes for other components. It is normal for models to pass a unique identifier to createIndex() to ensure the model index can be associated with its corresponding item.

index() Given a model index for a parent item, this method creates indexes for children of that item. If no valid child item can be found, the method must return QModelIndex().
parent() Provides the model index for the parent of any given item. If the model index is a top-level item or if there is no valid parent item, the method must return QModelIndex()

Parent Items

When requesting an index for a model item the parent item must be specified as shown in this example.

QModelIndex index = model->index(row, column, parent);

The diagram shows a tree model in which each item is referred to by a row number, a column number, and the parent.

Items A and C are both considered top-level items so their parent is an empty QModelIndex().

QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexC = model->index(2, 1, QModelIndex());

Retrieving the model index for item B requires passing the model index for item A, since B is a child of A.

QModelIndex indexB = model->index(1, 0, indexA);

Read Only Access to a Model

To implement a model which provides read only access to data the following methods must be implemented.

data() Supplies item data to views and delegates. Models only need to supply data for Qt::DisplayRole
headerData() Provides vertical and horizontal headers information, only used by views which can display headers.
rowCount() Returns the number of rows of data exposed by the model.
flags() Used by other components to obtain information about each item provided by the model.

The following method must be implemented in child classes of QAbstractTableModel and QAbstractItemModel.

columnCount() Returns the number of columns of data exposed by the model.

Editing Items

Most models provide the ability to edit items. The following methods must be implemented to support this operation.

setData() Modifies the data associated with a specified model index. This method must accept data associated with Qt::EditRole. After updating the data, the model must emit the dataChanged() signal.
setHeaderData() Used to modify vertical and horizontal header information. After updating the data, the model must emit the headerDataChanged() signal.
flags() The value returned by this method must include Qt::ItemIsEditable in addition to the values applied to items in a read-only model.

Resizing Models

Some models support adding and removing of rows. Table models and Tree models can also support adding and removing columns. It is important to notify other components about changes to the model dimensions just before and just after they occur. The following methods can be implemented to allow a model to be resized, however implementations must ensure the appropriate methods are called to notify views and delegates.

insertRows() Used to add new rows and items. Implementations must call beginInsertRows() before inserting new rows and then call endInsertRows() immediately afterwards.
removeRows() Used to remove rows and their items. Implementations must call beginRemoveRows() before inserting new columns and then call endRemoveRows() immediately afterwards.
insertColumns() Used to add new columns and items. Implementations must call beginInsertColumns() before rows are removed and then call endInsertColumns() immediately afterwards.
removeColumns() Used to remove columns and their items. Implementations must call beginRemoveColumns() before columns are removed and then call endRemoveColumns() immediately afterwards.

These methods should return true if the entire operation was successful. There may be situations where the operation only partially succeeded. For example, if less than the specified number of rows could be inserted. In this case the method must return false.

Normally the begin and end methods are sufficient to inform other components about changes to the model. For some complex changes to the model it will be necessary to emit the layoutChanged() signal.

Lazy population of Model Data

Lazy population of model data effectively allows requests for information about the model to be deferred until it is actually needed by views.

Some models need to obtain data from remote sources, or must perform time-consuming operations to obtain information about the way the data is organized. Since views generally request as much information as possible in order to accurately display model data, it can be useful to restrict the amount of information returned to them to reduce unnecessary follow-up requests for data.

In hierarchical models where finding the number of children of a given item is an expensive operation, it is useful to ensure that the model's rowCount() implementation is only called when necessary. In such cases, the hasChildren() method can be reimplemented to provide an inexpensive way for views to check for the presence of children and, in the case of QTreeView, draw the appropriate decoration for their parent item.

Whether the reimplementation of hasChildren() returns true or false, it may not be necessary for the view to call rowCount() to find out how many children are present. For example, QTreeView does not need to know how many children there are if the parent item has not been expanded to show them.

If it is known that many items will have children, reimplementing hasChildren() to unconditionally return true is sometimes a useful approach to take. This ensures that each item can be later examined for children while making initial population of model data as fast as possible. The only disadvantage is that items without children may be displayed incorrectly in some views until the user attempts to view the non-existent child items.

Performance optimization for large Data sets

The canFetchMore() method checks if the parent has more data available and returns true or false accordingly. The fetchMore() method fetches data based on the parent specified. For example, in a database query involving incremental data to populate a QAbstractItemModel it would make sense to implement both of these methods. Another example would be dynamically populating a tree model when a branch in the tree view is expanded.

If your reimplementation of fetchMore() adds rows to the model, calling the methods beginInsertRows() and endInsertRows() will be required.