CopperSpice API  1.9.1
Making Selections in a Model

Item Selection

A selection model is a subset of the items stored in a model. The QItemSelectionModel class is responsible for tracking which items are selected in a given model. A view uses QItemSelectionModel to highlight the items which are selected.

The view classes construct their own internal selection models. The name of the selection model used by a particular view can be obtained by calling the QAbstractItemView::selectionModel() method. A custom selection model can be specified by calling setSelectionModel(). The ability to set a new selection model on a view is useful when you want multiple views to share the same set of selected items. Unless you are implementiong a custom model or view, there is no need to change the contents of selections.

Sharing Selections between Views

If you have more than one view displaying data from the same model, it is often desirable to share the user selections. The code below configures viewTwo, to use the selection model used in viewOne. Both views now operate on the same selection model which will keep the set of selections synchronized.

viewTwo->setSelectionModel(viewOne->selectionModel());

Custom Selection Models

For most applications the default behavior of QItemSelectionModel is sufficient. If your design requirs something unique, you can create a custom selection model.

Selections are made up of "selection ranges". These efficiently maintain information about large selections of items by recording only the starting and ending model indexes for each range of selected items. Non-contiguous selections of items are constructed by using more than one selection range to describe the selection.

Selections are applied to a collection of model indexes held by a selection model. The most recent selection of items applied is known as the "current selection". The result of selecting a group of items can be modified, even after the current selection is made.

The indexes of all selected items can be retrieved and other components can be informed of changes to the selection model via signals and slots.

Current Item vs Selected Items

In any view there is always a current item and a groups of selected items which may not match. A given item can be the current item and also a selected item. The view is responsible for ensuring there is always a current item. Operations such as keyboard navigation require there to always be a current item.

The table below highlights the differences between current item and selected items.

Current ItemSelected Items
There can only be one current item at any time. More than one item can be selected.
A different current item can be selected by using key navigation or the mouse. Selected state of items can be set or unset by using key navigation or the mouse.
The current item is indicated by the focus rectangle. Selected items are highlighted with the selection rectangle.

Using a Selection Model

A selection is defined by passing a pair of model indexes to the constructor of QItemSelection. The indexes are the top-left and bottom-right items in a rectangular block of selected items. To apply the selection to items in a model requires the selection to be submitted to a selection model. This can be achieved in a number of ways, each having a different effect on the selections already present in the selection model.

Selecting Items

The following code will first construct a custom table model with 32 items and then create a table view to display the data. The default selection model from the view is retrieved and save for later. The variables topLeft and bottomRight are assigned to indicate the boundaries of our selection.

TableModel *model = new TableModel(8, 4, &app);
QTableView *table = new QTableView(nullptr);
table->setModel(model);
// save default selection model
QItemSelectionModel *selectionModel = table->selectionModel();
QModelIndex topLeft = model->index(0, 0, QModelIndex());
QModelIndex bottomRight = model->index(5, 2, QModelIndex());
// create and set the selection
QItemSelection region(topLeft, bottomRight);
selectionModel->select(region, QItemSelectionModel::Select);

The selection is made but calling selectionModel->select() and passing our region and a flag. In this code the flags used cause the items in the region to be come selected and the view will be updated. The selection of items can be modified using various operations defined by the selection flags.

Reading the Selection State

The model indexes stored in the selection model can be read using the selectedIndexes() method. This returns an unsorted list of model indexes which can be iterated over.

QModelIndexList indexes = selectionModel->selectedIndexes();
for (const QModelIndex &index : indexes) {
QString text = QString("(%1,%2)").formatArg(index.row()).formatArg(index.column());
model->setData(index, text);
}

The selection model emits signals to indicate changes in the selection. These signals notify other components about changes to the selection or the currently focused item in the item model. Connecting the selectionChanged() signal to a slot allows examining the items in the model which are selected or deselected. When the slot is called it will be passed two QItemSelection objects. One contains a list of indexes corresponding to the selected items and the other contains a list of indexes which correspond to the deselected items.

The following code implements an example of a slot which is invoked when the selectionChanged() signal is emitted. The first loop updates the contents of all selected items. The second loop erases the contents of the deselected items.

void MainWindow::updateSelection(const QItemSelection &selected, const QItemSelection &deselected)
{
for (const QModelIndex &index : selected.indexes()) {
QString text = QString("(%1,%2)").formatArg(index.row()).formatArg(index.column());
model->setData(index, text);
}
for (const QModelIndex &index : deselected.indexes()) {
model->setData(index, QString());
}
}

When the current item changes the currentChanged() signal will be emitted. The code shown below is an example of the slot which could be connected to this signal. When the slot is called it will be passed two QModelIndex objects. One contains the index for the new current item and the other is the index for the old current item.

void MainWindow::changeCurrent(const QModelIndex &current, const QModelIndex &previous)
{
statusBar()->showMessage(tr("Focus moved from (%1,%2) to (%3,%4)")
.formatArg(previous.row()).formatArg(previous.column())
.formatArg(current.row()).formatArg(current.column()));
}

Updating a Selection

Methods in QItemSelectionModel use a combination of flags defined by the enum QItemSelectionModel::SelectionFlag. Each flag value indicates how the selection model should update its internal list of selected items.

The most common flag is the QItemSelectionModel::SelectionFlag::Select which indicates the items should be selected. The QItemSelectionModel::SelectionFlag::Toggle flag causes the selection model to invert the state of the specified items. The QItemSelectionModel::SelectionFlag::Deselect flag deselects all the specified items.

The selection model is updated by constructing a QItemSelection object and passing the topLeft and bottomRight model indexes. The last step is to call select() and pass the new region.

topLeft = model->index(2, 1, QModelIndex());
bottomRight = model->index(7, 3, QModelIndex());
QItemSelection toggleRegion(topLeft, bottomRight);
selectionModel->select(toggleRegion, QItemSelectionModel::Toggle);

The results of this operation applied after the example in "Selecting Items" will produce the selections shown in the following image. The use of the Toggle flag means the elements in the center, which were selected, will now be deselected.

Row and Column Selections

The flags used to describe the selection command can be combined with additional flags to change entire rows and columns at one time. In this example both calls to select() are passed a new region.

In the first block the region includes two cells so every item in column 1 and column 2 will be selected. In the second block the region includes two different cells so every item in row 0 and row 1 will be selected.

// columns
topLeft = model->index(0, 1, QModelIndex());
bottomRight = model->index(0, 2, QModelIndex());
QItemSelection columnRegion(topLeft, bottomRight);
selectionModel->select(columnRegion, QItemSelectionModel::Select | QItemSelectionModel::Columns);
// rows
topLeft = model->index(0, 0, QModelIndex());
bottomRight = model->index(1, 0, QModelIndex());
QItemSelection rowRegion(topLeft, bottomRight);
selectionModel->select(rowRegion, QItemSelectionModel::Select | QItemSelectionModel::Rows);

The following image shows the result of these two selections.

Select all items in a Model

To clear every selection in a selection model use the Clear flag or call the clear() method. To select every item in the selection model it is a bit more complicated.

You will need to create a selection for every level of the model which includes every item at that level. The following example show how to select every item for a given level.

QModelIndex topLeft = model->index(0, 0, parent);
QModelIndex bottomRight = model->index(model->rowCount(parent)-1, model->columnCount(parent)-1, parent);
QItemSelection region(topLeft, bottomRight);
selectionModel->select(region, QItemSelectionModel::Select);