Home | All Classes | Main Classes | Annotated | Grouped Classes | Functions

Model Classes

Basic concepts

In the model/view architecture, the model's purpose is to manage data, and to provide a standard representation of that data to the other components in the framework. In Qt, the standard interface to item models is defined by the QAbstractItemModel class. This class exposes a table-like interface to other components, regardless of how the data is actually stored in the model, or presented to the user. It also notifies any attached views of changes to the model through the signals and slots mechanism.

This section describes some basic concepts that are central to the way models are accessed by other components. More advanced concepts are discussed later.

Model indices

To ensure that representation of the data in the model is kept separate from the way it is accessed, the concept of a model index is introduced. Each item of data is represented by a model index that is provided by the model when required. As a result, only the model needs to know how items are stored, and the type of data managed by the model can be defined fairly generally.

Model indices provide temporary references to items, and can be used to retrieve or modify their data. Since models may reorganize their internal structures from time to time, model indices may become invalid, and should not be stored. If a long-term reference to a model item is required, a persistent model index must be created. This provides a reference to the item that the model keeps up-to-date. Temporary model indices are provided by the QModelIndex class, and persistent model indices are provided by the QPersistentModelIndex class.

To obtain a model index for an item in a model, four properties must be specified: a row number, a column number, the index of a parent item, and an item type. The following subsections describe and explain these properties in detail.

Rows and columns

In its most basic form, an item model can be accessed as a simple table in which items are located by their row and column numbers. We can retrieve information about any given item by specifying its row and column numbers to the model, and we will receive an index that represents the item:

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

We can ask the model for the item's data by passing it the model index corresponding to the item:

    QVariant value = model->data(index, ...);

The following diagram shows a representation of a basic model in which each item is located by a pair of row and column numbers.

The highlighted item is represented by a model index that was obtained by specifying the relevant row and column numbers to the model.

Parents of items

A simple tabular model would be ideal for representing items in a table, or as a list of items. However, structures such as tree views require a more flexible interface to the items in the model. As a result, each item can also be used as the parent of another table of items, in much the same way that a top-level item in a tree view can contain another list of items.

When requesting an index for a model item, we must provide some information about the item's parent. Outside the model, the only way to refer to an item is through a model index, so a parent model index must be given:

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

The following diagram shows the row numbers, column numbers, and parent indices for two items in the model: a top-level item, and one of its children.

The model index of the highlighted top-level item is represented by the 'X' symbol, and this is given as the parent of the highlighted child item. Top-level items in a model do not have a parent model index to refer to, so we ensure that the model knows that we are referring to a top-level item by specifying a default (and invalid) model index. This is a convention used by the model/view classes. We can obtain the model indices for both items shown in the diagram:

    QModelIndex topLevelIndex = model->index(2, 1, QModelIndex(), ...); // 'X'
    QModelIndex childIndex = model->index(3, 4, topLevelIndex, ...);

Note that we used QModelIndex() to construct an invalid model index.

Item types and roles

Model indices are available in three different types: some indices refer to items shown in a view, some refer to items used as horizontal headers, and the rest refer to items used as vertical headers. By specifying different types, we only retrieve the kind of information that we need. Usually, we want to refer to the data that will be displayed in a view, so we specify the View type when obtaining the index. If we specify the HorizontalHeader or VerticalHeader types, the model can return an index corresponding to a horizontal or vertical header.

When we obtain a model index, we specify to the model the type of item we are interested in. The above diagram shows how different types of model indices correspond to items in the model. The model indices corresponding to the highlighted item and headers in the above diagram can be obtained by specifying the appropriate index types:

    QModelIndex itemIndex = model->index(1, 2, parent, QModelIndex::View);
    QModelIndex horHeaderIndex =
        model->index(1, 2, parent, QModelIndex::HorizontalHeader);
    QModelIndex verHeaderIndex =
        model->index(1, 2, parent, QModelIndex::VerticalHeader);

Note that, for most models, the horizontal header will be the same for all items in a column, and the vertical header will be the same for all items in a row. The model/view architecture is flexible enough to allow individual headers for each combination of row, column, and parent supplied. However, many views will not automatically take advantage of this capability.

Items in a model can perform various roles for other components, allowing different kinds of data to be supplied for different situations. For example, the DisplayRole role is used to access a string that can be displayed as text in a view. Typically, items contain data for a number of different roles. The role indicates to the model which kind of data is being referred to. We will examine roles in more detail when we create an example model.

Summary of concepts

Model indices contain information about the location of items within a model; they are constructed by models at the request of other components, such as views and delegates. Each model index refers to an item at a given row and column, and is assigned a particular type indicating what the item's data is used for. If a valid parent index is specified when an index is constructed, the index refers to a child of the corresponding parent item; otherwise the index refers to a top-level item in the model.

Where the item type distinguishes between items in a view and the headers, the role distinguishes between the different types of data associated with an item.

Using an existing model

One of the models provided by Qt is the QDirModel, a model that maintains information about the contents of a directory. This provides a ready-to-use model to experiment with, and can be easily set up with existing data. Using this model, we can show how to set up a model for use with ready-made views, and explore how to manipulate data using model indices.

Using views with a model

The QListView and QTreeView classes are the most suitable view to use with QDirModel. The example presented below displays the contents of a directory in a tree view next to the same information in a list view. The views share the user's selection so that the selected items are highlighted in both views.

We will first set up a QDirModel so that it is ready for use then create some views to display the contents of a directory. This shows the simplest pattern of use of a model. The construction and use of the model is performed from within a single main() function:

    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
        QSplitter *splitter = new QSplitter;

        QDirModel *model = new QDirModel(QDir(), splitter);

The model is set up to use data from a default directory, and is given an arbitrary widget as its parent object. The parent can be any subclass of QObject. We create two views so that we can examine the items held in the model:

        QTreeView *tree = new QTreeView(splitter);
        QListView *list = new QListView(splitter);

        tree->setModel(model);
        list->setModel(model);

The views are constructed in the same way as other widgets. Setting up a view to display the items in the model is simply a matter of calling its setModel() function with the directory model as the argument.

The rest of the function just displays the views within a splitter widget, and runs the application's event loop:

        splitter->setWindowTitle("Two views onto the same directory model");
        splitter->show();
        app.setMainWidget(splitter);

        return app.exec();
    }

In the above example, we neglected to mention how to handle selections of items. This subject is covered in more detail in the section of this document that deals with handling selections.

Using model indices

To demonstrate how data can be retrieved from a model, using model indices, we will set up a QDirModel without a view and print out the names of files and directories to a terminal. We will use the qDebug() function for this purpose. Although this does not show a normal way of using a model, it demonstrates the conventions used by models when dealing with model indices.

We construct a directory model in the same way as before:

        QDirModel *model = new QDirModel(QDir(), window);
        model->setFilter(QDir::All);
        int numRows = model->rowCount(QModelIndex());

In this case, we ensure that all files and directories are reported by the model by setting the file filter, and we count the number of rows in the model using the rowCount() function.

For simplicity, we are only interested in the items in the first column of the model. We examine each row in turn, obtaining a model index for the first item in each row, and reading the data stored for that item in the model.

        for (int row = 0; row < numRows; ++row) {
            QModelIndex index = model->index(row, 0, QModelIndex(), QModelIndex::View);

To obtain a model index, we specify the row number, column number (zero for the first column), the appropriate parent model index for top-level model items (the default invalid model index), and the type of information required. We want the View type of index because we need the information that would be displayed in a view, rather than the information used in a header.

The text stored in each item is retrieved using the model's data() function. We specify the model index and the DisplayRole to obtain data for the item in the form of a string.

            QString text = model->data(index, QAbstractItemModel::DisplayRole).toString();
            qDebug("%s", text.ascii());

        }

The above example demonstrates the basic principles used to retrieve data from a model:

Further reading

New models can be created by implementing the standard interface provided by QAbstractItemModel. We will demonstrate this by subclassing a standard model to provide a convenient ready-to-use model for holding strings.


Copyright © 2004 Trolltech. Trademarks
Qt 4.0.0-tp1