Qt Literacy-Qt Model/View Theory Summary [Part 2]

1. Handling the selection in Item view

1. Concept

The selection model used in the item view class provides a general description of selections based on the model/view architecture. While the standard classes for manipulating selections are sufficient for the provided item views, the selection model allows us to create specialized selection models to meet the needs of our own item models and views.

Information about the selected item in the view is stored in an instance of the QItemSelectionModel class. It maintains model indexes for items in a single model, independent of any views. Since a model can have multiple views, selections can be shared between views, allowing an application to display multiple views in a consistent manner.

Selections consist of selection ranges. These methods efficiently maintain information about large selections by recording only the start and end model indices of each range of selections. Build non-contiguous sets of selection items by using multiple selection ranges to describe selections;

The selection is applied to the collection of model indices held by the selection model. The most recently selected application is called the current selection. The effect of this selection can be modified by using certain types of selection commands even after it has been applied. These are discussed later in this section.

1. Current item and selected item

In a view, there is always a current item and a selected item, which are two separate states. An item can be the current item or the selected item at the same time. The view is responsible for making sure there is always a current item, eg keyboard navigation requires a current item.

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

current item selected item
There can only be one current item. There can be multiple selections.
The current item will change with keystroke navigation or mouse button clicks. When a user interacts with an item, whether the item's selection state is set or unset depends on several predefined modes—for example, single selection, multiple selection, etc.
If the edit key F2 is pressed or the item is double-clicked, the current item will be edited (provided that editing is enabled). The current element can be used with anchors to specify ranges for selection or deselection (or a combination of both).
The current item is represented by a focus rectangle. The selected item is represented by a selection rectangle.

When manipulating selections, QItemSelectionModel can generally be thought of as a record of the selection states of all items in an item model. Once the selection model is established, elements can be selected, deselected, or toggled between their selected states without knowing which elements are already selected. The indexes of all selected items can be obtained at any time, and other components can be notified of the change of the selection model through the signal and slot mechanism.

2. Use the selection model

The standard view class provides a default selection model that can be used in most applications. The selection model belonging to a view can be obtained using the view's selectionModel() function, and shared between multiple views via setSelectionModel(), so it is usually not necessary to construct a new selection model.
Create a selection by specifying a model and a pair of QItemSelection model indices. This uses indices to refer to items in the given model, and interprets them as top-left and bottom-right items in the selected items block. To apply a selection to an item in the model, the selection needs to be submitted to the selection model; this can be achieved in a number of ways, each of which has a different effect on selections already in the selection model.

1. Select item

In order to demonstrate some of the main features of selection, we build an instance of a custom table model with a total of 32 elements, and then open a table view to view the data in it:

TableModel *model = new TableModel(8, 4, &app);

QTableView *table = new QTableView(0);
table->setModel(model);

QItemSelectionModel *selectionModel = table->selectionModel();

The default selection model for the table view will be retrieved for later use. Instead of modifying any items in the model, we select some items that will be displayed in the upper left corner of the table. To do this, we need to get the model index corresponding to the upper left and lower right elements of the area to be selected:

QModelIndex topLeft;
QModelIndex bottomRight;

topLeft = model->index(0, 0, QModelIndex());
bottomRight = model->index(5, 2, QModelIndex());

To select these items in the model and see the corresponding changes in the tableview, a selection object needs to be constructed and then applied to the selection model:

QItemSelection selection(topLeft, bottomRight);
selectionModel->select(selection, QItemSelectionModel::Select);

Apply selection to the selection model using the command defined by the combination of selection flags.

In this case, the flag used causes the items recorded in the selection object to be included in the selection model, regardless of their previous state. The resulting selection is displayed in the view.
insert image description here

The selection of element items can be modified through various operations defined by the selection flags. The choices produced by these operations may have complex structures, but the choice model effectively represents these choices. When learning how to update a selection, we'll cover how to use the different selection flags to manipulate selected elements.

2. Read the selection state

The model index stored in the selection model can be read using the selectedindex() function. This function returns an unsorted list of model indices, which can be iterated as long as we know which model they are for:

const QModelIndexList indexes = selectionModel->selectedIndexes();

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

The code above uses a range-based for loop to iterate and modify the item at the index returned by the selection model.

The selection model emits signals to indicate changes in selection. They notify other components about changes to the overall selection and the currently focused item in the item model. We can connect the selectionChanged() signal to a slot function and check which item in the model is checked or unchecked when the selection changes.

The slot function is called with two QItemSelection objects: one containing a list of indices corresponding to the newly selected items; the other containing the indices corresponding to the newly deselected items.

In the code below, we provide a slot that receives the selectionChanged() signal, fills the selected item with a string, and clears the content of the deselected item.

void MainWindow::updateSelection(const QItemSelection &selected, const QItemSelection &deselected)
{
    
    
	QModelIndexList items = selected.indexes();

	for (const QModelIndex &index : qAsConst(items)) {
    
    
		QString text = QString("(%1,%2)").arg(index.row()).arg(index.column());
		model->setData(index, text);
	}

	items = deselected.indexes();

	for (const QModelIndex &index : qAsConst(items)) {
    
    
		model->setData(index, QString());
}

We can keep track of the currently focused element by connecting the currentChanged() signal to a slot function called with two model indices. These correspond to the previous focused item and the currently focused item, respectively.

In the code below, we provide a slot that receives the currentChanged() signal and use the provided information to update the QMainWindow's status bar:

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

The selections made by the user can be directly monitored through these signals, but we can also update the selection model directly.

3. Update the selection

Selection commands are provided by combinations of selection flags, defined by QItemSelectionModel::SelectionFlag. Each select flag tells the selection model how to update the internal record of selected items when any of the select() functions are called. The most commonly used flag is the Select flag, which instructs the selection model to record the specified item as selected. The toggle flag causes the selection model to invert the state of the specified items, that is, select any unselected items given, and deselect any currently selected items. The Deselect flag is used to deselect all specified items.

Individual items in the selection model are updated by creating an item selection and applying it to the selection model. In the code below, we apply a second selection of items to the table model shown above, using the Toggle command to toggle the selection state of a given item.

QItemSelection toggleSelection;

topLeft = model->index(2, 1, QModelIndex());
bottomRight = model->index(7, 3, QModelIndex());
toggleSelection.select(topLeft, bottomRight);

selectionModel->select(toggleSelection, QItemSelectionModel::Toggle);

The results of the operation are displayed in a table view, which provides a convenient way to visualize:
insert image description here
by default, select commands only operate on a single item specified by the model index. However, the flags used to describe select commands can be combined with other flags to change entire rows and columns. For example, if you call select() with only one index, but with a combination of select and Rows, the entire row containing the referenced item will be selected. The following code demonstrates how to use the Rows and Columns flags:

QItemSelection columnSelection;

topLeft = model->index(0, 1, QModelIndex());
bottomRight = model->index(0, 2, QModelIndex());

columnSelection.select(topLeft, bottomRight);

selectionModel->select(columnSelection,
QItemSelectionModel::Select | QItemSelectionModel::Columns);

QItemSelection rowSelection;

topLeft = model->index(0, 0, QModelIndex());
bottomRight = model->index(1, 0, QModelIndex());

rowSelection.select(topLeft, bottomRight);

selectionModel->select(rowSelection,
QItemSelectionModel::Select | QItemSelectionModel::Rows);

Although only 4 indices are provided to the select model, using the row and column select flags means that two columns and two rows are selected. The image below shows the result of both selections:
insert image description here

The commands executed on the example model all involve accumulating items selected in the model. You can also clear the selection, or replace the current selection with a new one.

To replace the current selection with a new one, the other selection markers need to be merged with the current one. Commands using this flag instruct the select model to replace the current set of model indices with the indices specified when calling select(). To clear all selections before starting to add new selections, combine the other selections flag with the clear flag. This has the effect of resetting the collection of model indices for the selected model.

4. Select all items in the model

In order to select all items in model, a selection needs to be created for each layer of model that covers all items in that layer. To do this, the indices corresponding to the top-left and bottom-right elements can be retrieved using a given parent index:

QModelIndex topLeft = model->index(0, 0, parent);
QModelIndex bottomRight = model->index(model->rowCount(parent)-1,
model->columnCount(parent)-1, parent);

Use these indicators and models for selection. Then select the corresponding item in the selection model:

QItemSelection selection(topLeft, bottomRight);
selectionModel->select(selection, QItemSelectionModel::Select);

This needs to be done for all levels in the model. For top-level elements, we'll define the parent index in the usual way:

QModelIndex parent = QModelIndex();

In a hierarchical model, the hasChildren() function is used to determine whether an item is a parent element of another item.

2. Create a new model

The functional separation between model/view components allows for the creation of models that can leverage existing views. This approach allows us to use standard GUI components such as QListView, QTableView, and QTreeView to present data from various sources.

The QAbstractItemModel class provides an interface flexible enough to support data sources that arrange information in a hierarchy, allowing data to be inserted, deleted, modified, or sorted in some way. It also supports drag and drop.

The QAbstractListModel and QAbstractTableModel classes provide interface support for simpler, non-hierarchical data structures, and are easier to use as starting points for simple list and table models.

In this section, we'll create a simple read-only model to explore the basic principles of the model/view architecture. Later in this section, we'll adapt this simple model so that users can modify items.

1. Design a model

When creating a new model for an existing data structure, it is important to consider what type of model should be used to provide an interface to the data. If the data structure can be represented as a list or table of items, subclasses of QAbstractListModel or QAbstractTableModel can be created, as these classes provide suitable default implementations for many functions.

However, if the underlying data structure can only be represented by a hierarchical tree structure, it is necessary to subclass QAbstractItemModel. The simple tree model example takes this approach.

In this section, we will implement a simple model based on a list of strings, so QAbstractListModel provides an ideal base class to build upon.

Whatever form the underlying data structure takes, it's usually a good idea to supplement the standard QAbstractItemModel API with an API that allows more natural access to the underlying data structure in specialized models. This makes it easier to populate the model with data, but still allows other generic model/view components to interact with it using the standard API. The model described below provides a custom constructor for this purpose.

2. Read-only example model

The model implemented here is a simple, non-hierarchical, read-only data model based on the standard QStringListModel class. It has a QStringList as its internal data source and implements only what is needed to create a functional model. To make implementation easier, we subclass QAbstractListModel because it defines sensible default behavior for the list model, and it exposes a simpler interface than the QAbstractItemModel class.

When implementing the model, it is important to remember that QAbstractItemModel does not store any data itself, it just provides the interface that the view uses to access the data. For a minimal read-only model, only a few functions need to be implemented, since most interfaces have default implementations. The class declaration is as follows:

class StringListModel : public QAbstractListModel
{
    
    
Q_OBJECT

public:
StringListModel(const QStringList &strings, QObject *parent = nullptr)
: QAbstractListModel(parent), stringList(strings) {
    
    }

int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;

private:
QStringList stringList;
};

In addition to the model's constructor, we only need to implement two functions: rowCount() returns the number of rows in the model, and data() returns an item of data corresponding to the specified model index.

Well-behaved models also implement headerData() to provide tree views and table views with content to display in their headers.

Note that this is a non-hierarchical model, so we don't have to worry about parent-child relationships. If our model is hierarchical, we must also implement the index() and parent() functions.

The list of strings is stored internally in the stringList private member variable.

1. The size of the model

We want the number of rows in model to be the same as the number of strings in the list of strings. We implement the rowCount() function like this:

int StringListModel::rowCount(const QModelIndex &parent) const
{
    
    
return stringList.count();
}

Since model is non-hierarchical, we can safely ignore the model index corresponding to the parent. By default, models derived from QAbstractListModel contain only one column, so we don't need to reimplement the columnCount() function.

2. model header and data

For the items in view, we want to return the strings in the list of strings. The data() function is responsible for returning the data item corresponding to the index parameter:

QVariant StringListModel::data(const QModelIndex &index, int role) const
{
    
    
if (!index.isValid())
return QVariant();

if (index.row() >= stringList.size())
return QVariant();

if (role == Qt::DisplayRole)
return stringList.at(index.row());
else
return QVariant();
}

We return a valid QVariant only if the provided model index is valid, the row number is within the range of entries in the string list, and the requested role is one we support.
Some views, such as QTreeView and QTableView, can display the title along with the item data. If our model is displayed in a view with a header, we want the header to display the row and column numbers. We can provide information about header files by subclassing the headerData() function:

QVariant StringListModel::headerData(int section, Qt::Orientation orientation,
 int role) const
{
    
    
if (role != Qt::DisplayRole)
return QVariant();

if (orientation == Qt::Horizontal)
return QStringLiteral("Column %1").arg(section);
else
return QStringLiteral("Row %1").arg(section);
}

Likewise, we return a valid QVariant only if the character is one we support. Also consider the heading's orientation when deciding on the exact data to return.

Not all views display headers with item data, and those that do may be configured to hide them. Nevertheless, it is recommended that we implement the headerData() function to provide relevant information about the data provided by the model.

An item can have multiple roles, and different data will be given according to the specified roles. Items in our model have only one role, DisplayRole, so we return the item's data regardless of the assigned role. However, we can reuse the data provided for DisplayRole in other roles, for example view can use ToolTipRole to display item information in tooltip.

3. Editable model

The read-only model shows how to present simple selections to the user, but for many applications the editable list model is more useful. We can modify the read-only model to make the item editable by modifying the data() function we implemented for read-only, and implementing two additional functions: flags() and setData(). The following function declarations are added to the class definition:

Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value,
 int role = Qt::EditRole) override;

1. Make the model editable

The delegate checks whether an item is editable before creating an editor. The model must let the delegate know that its items are editable. We do this by returning the correct flags for each item in the model; in this case, we enable all items, and make them both selectable and editable:

Qt::ItemFlags StringListModel::flags(const QModelIndex &index) const
{
    
    
if (!index.isValid())
return Qt::ItemIsEnabled;

return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}

Note that we don't need to know how the delegate performs the actual editing process. We just need to provide a way for the delegate to set the data in the model. This is achieved with the setData() function:

bool StringListModel::setData(const QModelIndex &index,
const QVariant &value, int role)
{
    
    
if (index.isValid() && role == Qt::EditRole) {
    
    

stringList.replace(index.row(), value.toString());
emit dataChanged(index, index, {
    
    role});
return true;
}
return false;
}

In this model, the entry in the list of strings corresponding to the model index is replaced with the supplied value. However, before modifying a list of strings, you must ensure that the index is valid, that the items are of the correct type, and that roles are supported. By convention, we stick to the role being EditRole, since that's what the standard item delegate uses.

However, for boolean values ​​we can use Qt::CheckStateRole and set the Qt::ItemIsUserCheckable flag; then use a checkbox to edit the value. The underlying data in this model is the same for all actors, so this detail makes it easier to integrate the model with standard components.

After setting the data, the model must let the view know that some data has changed. This is done by emitting the datachchanged() signal. Since only one item of data has changed, the range of items specified in the signal is limited to one model index.

Also, the data() function needs to be changed to add the Qt::EditRole test:

QVariant StringListModel::data(const QModelIndex &index, int role) const
{
    
    
if (!index.isValid())
return QVariant();

if (index.row() >= stringList.size())
return QVariant();

if (role == Qt::DisplayRole || role == Qt::EditRole)
return stringList.at(index.row());
else
return QVariant();
}

2. Insert and delete rows

The number of rows and columns in the model can be changed. In the string list model, it only makes sense to change the number of rows, so we only reimplement the functions for inserting and deleting rows. These are declared in the class definition:

bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;

Since rows in this model correspond to strings in the list, the insertRows() function inserts some empty strings into the list of strings before the specified position. The number of strings inserted is equal to the specified number of rows.

The parent index is typically used to determine where in the model the row should be added. In this example, we only have a top-level list of strings, so we just need to insert empty strings into the list.

bool StringListModel::insertRows(int position, int rows, const QModelIndex &parent)
{
    
    
beginInsertRows(QModelIndex(), position, position+rows-1);

for (int row = 0; row < rows; ++row) {
    
    
stringList.insert(position, "");
}

endInsertRows();
return true;
}

The model first calls the beginInsertRows() function to notify other components of the number of rows that will change. The function specifies the row numbers of the first and last row to insert, and the model index of their parent. After changing the list of strings, it calls endInsertRows() to complete the operation and notify other components that the dimensions of the model have been changed, returning true to indicate success.

Functions that delete rows from the model are also easy to write. The row to delete from model is specified by the given position and number of rows. To simplify the implementation, we ignore the parent index and just remove the corresponding item from the list of strings.

 bool StringListModel::removeRows(int position, int rows, const QModelIndex &parent)
{
    
    
beginRemoveRows(QModelIndex(), position, position+rows-1);

for (int row = 0; row < rows; ++row) {
    
    
stringList.removeAt(position);
}

endRemoveRows();
return true;
}

The beginRemoveRows() function is always called before any underlying data is removed, and specifies the first and last row to be removed. This allows other components to access the data before it becomes unavailable. After removing rows, the model issues endRemoveRows() to complete the operation and let other components know that the model's dimensions have changed.

3. Next steps

We can display the model's items in a vertical list using the QListView class, displaying data provided by that model or any other model. For the string list model, the view also provides a default editor so that the item can be operated. In the view class we check the possibilities offered by the standard view classes.

The model subclassing reference document discusses the requirements of QAbstractItemModel subclasses in more detail, and provides guidance on the virtual functions that must be implemented to enable various features in different types of models.

3. Item-based view convenience class

Item-based controls have names that reflect their purpose: QListWidget provides a list of items, QTreeWidget displays a multilevel tree structure, and QTableWidget provides a table of cell items. Each class inherits the behavior of the QAbstractItemView class, which implements the general behavior of item selection and title management.

1. QListWidget

A single level list of items is usually displayed using a QListWidget and some QListWidgetItems. List controls are constructed in the same way as other controls:

QListWidget *listWidget = new QListWidget(this);

List items can be added directly to the list control after construction:

new QListWidgetItem(tr("Sycamore"), listWidget);
new QListWidgetItem(tr("Chestnut"), listWidget);
new QListWidgetItem(tr("Mahogany"), listWidget);

They can also be constructed without a parent list widget and added to the list at a later time:

QListWidgetItem *newItem = new QListWidgetItem;
newItem->setText(itemText);
listWidget->insertItem(row, newItem);

Each item in the list can display a text label and an icon. The color and font used to render the text can be changed to give the item a custom look. Tooltips, status prompts, and "What's this?" help are all easily configurable to ensure the list is properly integrated into the application.

 newItem->setToolTip(toolTipText);
newItem->setStatusTip(toolTipText);
newItem->setWhatsThis(whatsThisText);

By default, items in the list are displayed in the order in which they were created. The item list can be sorted according to the criteria given in Qt::SortOrder to produce an alphabetically sorted item list:

listWidget->sortItems(Qt::AscendingOrder);
listWidget->sortItems(Qt::DescendingOrder);

2. QTreeWidget control

The QTreeWidget and QTreeWidgetItem classes provide a tree or hierarchical list of items. Each item in a tree control can have its own child items and can display information for many columns. Create a tree window control just like any other window control:

 QTreeWidget *treeWidget = new QTreeWidget(this);

The number of columns must be set before adding items to the tree control. For example, we can define two columns and create a header to provide labels at the top of each column:

treeWidget->setColumnCount(2);
QStringList headers;
headers << tr("Subject") << tr("Default");
treeWidget->setHeaderLabels(headers);

The easiest way to set labels for each section is to provide a list of strings. For more complex headers, we can construct a tree item, decorate it as we wish, and use it as the tree control's header.

Top-level items in a tree control are constructed with the tree control as their parent. They can be inserted in any order, or we can ensure they are listed in a specific order by specifying the previous item when constructing each item:

QTreeWidgetItem *cities = new QTreeWidgetItem(treeWidget);
cities->setText(0, tr("Cities"));
QTreeWidgetItem *osloItem = new QTreeWidgetItem(cities);
osloItem->setText(0, tr("Oslo"));
osloItem->setText(1, tr("Yes"));

QTreeWidgetItem *planets = new QTreeWidgetItem(treeWidget, cities);

The tree control handles top-level items slightly differently than other items deeper in the tree. Items can be removed from the top level of the tree by calling the tree control's takeTopLevelItem() function, but items are removed from lower levels by calling the takeChild() function of its parent item. Use the insertTopLevelItem() function to insert items at the top level of the tree. At lower levels in the tree, use the parent's insertChild() function.

Moving items between the top and lower levels of the tree is easy. We just need to check if the item is a top-level item, this information is provided by each item's parent() function. For example, we can delete the current item in a tree control regardless of its position:

     QTreeWidgetItem *parent = currentItem->parent();
      int index;

      if (parent) {
    
    
          index = parent->indexOfChild(treeWidget->currentItem());
          delete parent->takeChild(index);
      } else {
    
    
          index = treeWidget->indexOfTopLevelItem(treeWidget->currentItem());
          delete treeWidget->takeTopLevelItem(index);
      }

Inserting items elsewhere in the tree control follows the same pattern:

      QTreeWidgetItem *parent = currentItem->parent();
      QTreeWidgetItem *newItem;
      if (parent)
          newItem = new QTreeWidgetItem(parent, treeWidget->currentItem());
      else
          newItem = new QTreeWidgetItem(treeWidget, treeWidget->currentItem());

3. QTableWidget

Tables of items similar to those found in spreadsheet applications are constructed using QTableWidget and QTableWidgetItem. They provide a scrolling table control with headings and items to use in it.

Tables can be created with a certain number of rows and columns, or they can be added to tables of indeterminate size as needed.

     QTableWidget *tableWidget;
      tableWidget = new QTableWidget(12, 3, this);

Items are constructed outside the table and then added to the table at the desired location:

   QTableWidgetItem *newItem = new QTableWidgetItem(tr("%1").arg(
          pow(row, column+1)));
      tableWidget->setItem(row, column, newItem);

Horizontal and vertical headers can be added to a table by constructing items outside the table and using them as headers:

      QTableWidgetItem *valuesHeaderItem = new QTableWidgetItem(tr("Values"));
      tableWidget->setHorizontalHeaderItem(0, valuesHeaderItem);

Note that the rows and columns in the table start from 0.

4. Common features

Each convenience class has a number of item-based public features available through the same interface in each class. We describe these features in the following sections and provide some examples of the different controls. See the list of model/view classes for each control for more details on each function used.

1. Hidden items

Sometimes it is useful to hide items in the item view control instead of removing them. Items for all of the above controls can be hidden and shown later. We can determine whether an item is hidden by calling the isItemHidden() function, and we can use setItemHidden() to hide an item.
Since this operation is item-based, the same functions are available for all three convenience classes.

2. Select

The way an item is selected is controlled by the control's selection mode (QAbstractItemView::SelectionMode). This property controls whether the user can select one or more items, and in multi-item selections, whether the selection must be a contiguous range of items. Selection mode works the same way for all of the above controls.

Single Selection : The default SingleSelection mode is most appropriate when the user needs to select a single item from the control. In this mode, the current item and the selected item are the same.
insert image description here

Multiple item selection : In this mode, the user can toggle the selection state of any item in the control without changing the existing selection, much in the same way that non-exclusive checkboxes can be toggled independently.
insert image description here

Extended Selection : Controls that typically require the selection of many adjacent items, such as controls in a spreadsheet, need to use the ExtendedSelection mode. In this mode, a contiguous range of items in the control can be selected with the mouse and keyboard. If modifier keys are used, complex selections can also be created, including many items that are not adjacent to other selected items in the control.
insert image description here

If the user selects an item without using a modifier key, clears the existing selection.

Use the selectedItems() function to read the selected items in the control and provide an iterable list of related items. For example, we can find the sum of all values ​​in the selected item list with the following code:

      const QList<QTableWidgetItem *> selected = tableWidget->selectedItems();
      int number = 0;
      double total = 0;

      for (QTableWidgetItem *item : selected) {
    
    
          bool ok;
          double value = item->text().toDouble(&ok);

          if (ok && !item->text().isEmpty()) {
    
    
              total += value;
              number++;
          }
      }

Note that for single selection mode, the current item will be in the selection. In multiple selection and extended selection modes, the current item may not be in the selection, depending on how the user forms the selection.

3. Search

It is often useful to be able to look up items in an item view control, either as a developer or as a service provided to users. All three item view convenience classes provide a common findItems() function to make it as consistent and simple as possible.

Searches for text contained in entries according to criteria specified by a set of values ​​in Qt::MatchFlags. We can get a list of matching items using the findItems() function:

      const QList<QTreeWidgetItem *> found = treeWidget->findItems(
          itemText, Qt::MatchWildcard);

      for (QTreeWidgetItem *item : found) {
    
    
          item->setSelected(true);
          // Show the item->text(0) for each item.
      }

The above code causes the item in the tree control to be selected when it contains the text given in the search string. This mode is also available for list and table controls.

4. Use drag and drop item view

Qt's drag and drop infrastructure is fully supported by the model/view framework. Items in lists, tables, and trees can be dragged in the view, and data can be imported and exported as mime-encoded data.

Standard views automatically support drag and drop internally, allowing items to be moved to change the order in which they are displayed. By default, these views do not support drag and drop, since they are configured for the simplest and most common use. To allow dragging of an item, certain properties of the view need to be enabled, and the item itself must also allow dragging.
A model that only allows items to be exported from the view, and doesn't allow data to be put into it, has fewer needs than a fully enabled drag-and-drop model.

1. Easy to use view

By default, each type of item used by QListWidget, QTableWidget, and QTreeWidget is configured to use a different set of flags. For example, each QListWidgetItem or QTreeWidgetItem is initially enabled, inspectable, selectable, and can be used as a source for drag-and-drop operations; each QTableWidgetItem can also be edited and used as a target for drag-and-drop operations.

While all of the standard items set a flag or two for drag and drop, you'll usually need to set various properties on the view itself to take advantage of the built-in drag and drop support:

  • To enable item dragging, set the view's dragEnabled property to true.
  • To allow users to drop internal or external items in a view, set the acceptDrops property of the view's viewport() to true.
  • To show the user where the currently dropped item was when it was dropped, set the view's showDropIndicator property. This provides the user with continuously updated information about the position of the item in the view.

For example, we can enable drag and drop functionality in a list control with the following line of code:

  QListWidget *listWidget = new QListWidget(this);
  listWidget->setSelectionMode(QAbstractItemView::SingleSelection);
  listWidget->setDragEnabled(true);
  listWidget->viewport()->setAcceptDrops(true);
  listWidget->setDropIndicatorShown(true);

The result is a list control that allows items to be copied within views, and even allows users to drag items between views that contain the same type of data. In both cases, items are copied rather than moved.

In order for the user to be able to move items in the view, we must set the dragDropMode of the list control:

listWidget->setDragDropMode(QAbstractItemView::InternalMove);

1. Use model / view classes

Views set up for drag and drop follow the same pattern as convenience views. For example, a QListView can be set up in the same way as a QListWidget:

  QListView *listView = new QListView(this);
  listView->setSelectionMode(QAbstractItemView::ExtendedSelection);
  listView->setDragEnabled(true);
  listView->setAcceptDrops(true);
  listView->setDropIndicatorShown(true);

Since access to the data displayed by the view is controlled by the model, the model used must also provide support for drag-and-drop operations. The operations supported by the model can be specified by reimplementing the QAbstractItemModel::supporteddroptions() function. For example, use the following code to enable copy and move operations:

  Qt::DropActions DragDropListModel::supportedDropActions() const
  {
    
    
      return Qt::CopyAction | Qt::MoveAction;
  }

Although any combination of values ​​in Qt::droptions can be given, the model needs to be written to support them. For example, to allow Qt::MoveAction to be used correctly with a list model, the model must provide an implementation of QAbstractItemModel::removeRows(), either directly or inherited from a base class.

2. Support drag and drop for item

By reimplementing the QAbstractItemModel::flags() function to provide the appropriate flags, the model indicates to the view which items are draggable and which are accepted.

For example, a model that provides a simple list based on QAbstractListModel can enable drag and drop operations on each item by ensuring that the returned flags contain the Qt::ItemIsDragEnabled and Qt::ItemIsDropEnabled values:

  Qt::ItemFlags DragDropListModel::flags(const QModelIndex &index) const
  {
    
    
      Qt::ItemFlags defaultFlags = QStringListModel::flags(index);

      if (index.isValid())
          return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
      else
          return Qt::ItemIsDropEnabled | defaultFlags;
  }

Note that items can be dragged and dropped on top of the model, but only valid items can be dragged.

In the above code, since the model is derived from QStringListModel, we get a set of default flags by calling the implementation of the flags() function.

3. Encode the exported data

When data items are exported from the model via drag-and-drop operations, they are encoded into the appropriate format for one or more MIME types. Models declare the MIME types they can use to provide items by reimplementing the QAbstractItemModel::mimeTypes() function, returning a list of standard MIME types.
For example, a model that only provides plain text would provide the following implementation:

  QStringList DragDropListModel::mimeTypes() const
  {
    
    
      QStringList types;
      types << "application/vnd.text.list";
      return types;
  }

The model must also provide code, encoding the data in the ad format. This is achieved by reimplementing the QAbstractItemModel::mimeData() function to provide a QMimeData object, just like in any other drag-and-drop operation.
The code below shows how to encode each item of data corresponding to a given index list into plain text and store it in a QMimeData object.

  QMimeData *DragDropListModel::mimeData(const QModelIndexList &indexes) const
  {
    
    
      QMimeData *mimeData = new QMimeData;
      QByteArray encodedData;

      QDataStream stream(&encodedData, QIODevice::WriteOnly);

      for (const QModelIndex &index : indexes) {
    
    
          if (index.isValid()) {
    
    
              QString text = data(index, Qt::DisplayRole).toString();
              stream << text;
          }
      }

      mimeData->setData("application/vnd.text.list", encodedData);
      return mimeData;
  }

Since a list of model indices is provided to the function, this method is general enough to work with both hierarchical and non-hierarchical models.
Note that custom data types must be declared as meta-objects, and stream operators must be implemented for them. See the QMetaObject class description for details.

4. Insert the deleted data into the model

The way any given model handles missing data depends on its type (list, table, or tree) and the way its contents might be presented to the user. In general, the method used to accommodate missing data should be the method most suitable for the model's underlying data storage.
Different types of models tend to handle missing data in different ways. The list and table models simply provide a flat structure for storing data items. So they may insert new rows (and columns) when data is deleted on existing items in the view, or they may overwrite the item contents in the model with some data provided. A tree model is often able to add children containing new data to its underlying data store, so its behavior is more predictable as far as the user is concerned.
Dropped data is handled by a model's reimplementation of QAbstractItemModel::dropMimeData(). For example, a model that handles simple lists of strings could provide an implementation that handles data put on existing items separately from data put on top of the model (that is, data put on invalid items).
By reimplementing QAbstractItemModel::canDropMimeData(), the model can forbid the deletion of certain items, or depend on the data being dropped.
The model must first ensure that the operation should be performed, that the provided data is in a consumable format, and that its destination in the model is valid:

  bool DragDropListModel::canDropMimeData(const QMimeData *data,
      Qt::DropAction action, int row, int column, const QModelIndex &parent)
  {
    
    
      Q_UNUSED(action);
      Q_UNUSED(row);
      Q_UNUSED(parent);

      if (!data->hasFormat("application/vnd.text.list"))
          return false;

      if (column > 0)
          return false;

      return true;
  }
  bool DragDropListModel::dropMimeData(const QMimeData *data,
      Qt::DropAction action, int row, int column, const QModelIndex &parent)
  {
    
    
      if (!canDropMimeData(data, action, row, column, parent))
          return false;

      if (action == Qt::IgnoreAction)
          return true;

A simple single-column string list model can indicate failure if the data provided is not plain text, or if an invalid column number is specified for deletion.
Data to be inserted into the model is handled differently depending on whether it is placed on an existing item. In this simple example, we want to allow placing items between existing items, before the first item in the list, and after the last item.

When a deletion occurs, the model index corresponding to the parent item is either valid, indicating that the deletion occurred on an item, or invalid, indicating that the deletion occurred somewhere in the view corresponding to the top level of the model.

   int beginRow;

      if (row != -1)
          beginRow = row;

We first check the provided row number to see if it can be used to insert an item into the model regardless of whether the parent index is valid.

else if (parent.isValid())
          beginRow = parent.row();

Deletion occurs on items if the parent model index is valid. In this simple list model, we find out the item's row number and use that value to insert the deleted item at the top level of the model.

     else
          beginRow = rowCount(QModelIndex());

When a drag and drop occurs elsewhere in the view, and line numbers are not available, we append the item to the top level of the model.
In a hierarchical model, when an item is dragged and dropped, it is best to insert the new item into the model as a child of that item. In the simple example shown here, the model has only one level, so this approach is not suitable.

5. Decode the imported data

Every implementation of dropMimeData() must also decode the data and insert it into the model's underlying data structure.
For a simple string list model, encoded items can be decoded and streamed into a QStringList:

      QByteArray encodedData = data->data("application/vnd.text.list");
      QDataStream stream(&encodedData, QIODevice::ReadOnly);
      QStringList newItems;
      int rows = 0;

      while (!stream.atEnd()) {
    
    
          QString text;
          stream >> text;
          newItems << text;
          ++rows;
      }

The string can then be inserted into the underlying data store. For consistency, this can be done through the model's own interface:

      insertRows(beginRow, rows, QModelIndex());
      for (const QString &text : qAsConst(newItems)) {
    
    
          QModelIndex idx = index(beginRow, 0, QModelIndex());
          setData(idx, text);
          beginRow++;
      }

      return true;
  }

Note that the model usually needs to provide implementations of the QAbstractItemModel::insertRows() and QAbstractItemModel::setData() functions.

5. Proxy model

In the model/view framework, data items provided by a single model can be shared by any number of views, and each view may represent the same information in a completely different way. Custom views and delegates are an effective way to provide completely different representations of the same data. However, applications often need to provide regular views for processed versions of the same data, such as views that sort a list of items differently.

While it might seem appropriate to perform the sorting and filtering operations as internal functions of the view, this approach does not allow multiple views to share the results of such potentially expensive operations. Another approach (involving sorting within the model itself) leads to similar problems, in that each view must display data items organized according to the most recent processing operations.

To solve this problem, the model / view framework uses a proxy model to manage the information provided between each model and view. From the perspective of the view, a proxy model is a component that behaves like a normal model and accesses data in the source model on behalf of the view. The signals and slots used by the model/view framework ensure that each view is updated appropriately, no matter how many proxy models are placed between itself and the source model.

1. Use proxy model

A proxy model can be inserted between an existing model and any number of views. Qt provides a standard proxy model, QSortFilterProxyModel, which is usually instantiated and used directly, but can also be subclassed to provide custom filtering and sorting behavior. The QSortFilterProxyModel class can be used in the following ways:

      QSortFilterProxyModel *filterModel = new QSortFilterProxyModel(parent);
      filterModel->setSourceModel(stringListModel);

      QListView *filteredView = new QListView;
      filteredView->setModel(filterModel);

Since proxy models inherit from QAbstractItemModel, they can be connected to any type of view and can be shared between views. They can also be used to process information obtained from other agent models in the pipeline arrangement.
The QSortFilterProxyModel class is designed to be instantiated and used directly in the application. More specialized proxy models can be created by subclassing this class and implementing the required comparison operations.

2. Custom proxy model

Typically, the type of processing used in a proxy model involves mapping each data item from its original location in the source model to a different location in the proxy model. In some models, some items may not have a corresponding position in the proxy model; these models are filter proxy models. The view accesses items using model indices provided by the proxy model, which contain no information about the source model or the position of the original item within that model.

QSortFilterProxyModel allows filtering of data in the source model before providing it to the view, and also allows the content of the source model to be provided to the view as pre-sorted data.

1. Custom filter model

The QSortFilterProxyModel class provides a fairly general filtering model that can be used in a variety of common situations. For advanced users, QSortFilterProxyModel can be subclassed to provide a mechanism that allows custom filters to be implemented.
Subclasses of QSortFilterProxyModel can reimplement two virtual functions that are called when requested from the proxy model or when using the model index:

  • filterAcceptsColumn() is used to filter specific columns from part of the source model.
  • filterAcceptsRow() is used to filter specific rows from part of the source model.

Default implementations of the above functions in QSortFilterProxyModel return true to ensure that all items are passed to the view; reimplementations of these functions should return false to filter out individual rows and columns.

2. Custom sorting model

A QSortFilterProxyModel instance uses the std::stable_sort() function to set up a mapping between items in the source model and items in the proxy model, allowing a sorted item hierarchy to be exposed to the view without modifying the source model structure. To provide custom sorting behavior, the lessThan() function needs to be reimplemented to perform custom comparisons.

3. Model subclassing reference

Model subclasses are required to provide implementations of many of the virtual functions defined in the QAbstractItemModel base class. The number of these functions that need to be implemented depends on the type of model - whether it provides a simple list, a table or a complex item hierarchy for the view. Models that inherit from QAbstractListModel and QAbstractTableModel can take advantage of the default implementations of the functions provided by these classes. A model that exposes data items in a tree structure must provide implementations for many virtual functions in qab

6. Model subclassing reference

Model subclasses are required to provide implementations of many of the virtual functions defined in the QAbstractItemModel base class. The number of these functions that need to be implemented depends on the type of model - whether it provides a simple list, a table or a complex item hierarchy for the view. Models that inherit from QAbstractListModel and QAbstractTableModel can take advantage of the default implementations of the functions provided by these classes. A model that exposes data items in a tree structure must provide implementations for many of the virtual functions in QAbstractItemModel.

The functions that need to be implemented in model subclasses can be divided into three groups:

  • **item data processing**: All models need to implement functionality that enables views and delegates to query the model's dimensions, inspect items, and retrieve data.
  • Navigation and Index Creation : Hierarchical models need to provide functions that views can call to navigate the tree structure they expose and obtain the model index for an item.
  • Drag and drop support and MIME type handling : model inherits functions that control how internal and external drag and drop operations are performed. These functions allow data items to be described with MIME types that other components and applications can understand.

1. Item data processing

Models may provide different levels of access to the data they provide: they may be simple read-only components, some models may support resizing operations, while others may allow editing of items.

2. Read-only access

In order to provide read-only access to data provided by a model, the following functions must be implemented in subclasses of model:

Function name function
flags() Used by other components to get information about each item provided by the model. In many models, the combination of flags should include Qt::ItemIsEnabled and Qt::ItemIsSelectable.
data() Used to provide item data to views and delegates. In general, the model only needs to provide data for Qt::DisplayRole and any application-specific user roles, but it is also good practice to provide data for Qt::ToolTipRole, Qt::AccessibleTextRole and Qt::AccessibleDescriptionRole. See the Qt::ItemDataRole enum documentation for information on the types associated with each role.
headerData () Provides the view with information to display in its title. Only views that can display header information can retrieve this information.
rowCount () Provides the number of rows of data exposed by the model.

The above four functions must be implemented in all types of models, including list models (QAbstractListModel subclasses) and table models (QAbstractTableModel subclasses).

Additionally, the following functions must be implemented in direct subclasses of QAbstractTableModel and QAbstractItemModel:

Function name function
columnCount () Provides the number of data columns exposed by the model. The list model does not provide this function because it is already implemented in QAbstractListModel.

1. Editable items

An editable model allows modification of data items and may also provide functions that allow insertion and deletion of rows and columns. To enable editing functionality, the following functions must be properly implemented:

Function name function
flags() The appropriate combination of flags must be returned for each item. Specifically, the value returned by this function must include Qt::ItemIsEditable in addition to the value that applies to items in the read-only model.
setData () Used to modify the data item associated with the specified model index. In order to be able to accept user input provided by user interface elements, this function must handle data related to Qt::EditRole. Implementations can also accept data associated with many different types of roles specified by Qt::ItemDataRole. After changing a data item, the model must emit the datachchanged() signal to notify other components of the change.
setHeaderData () Used to modify horizontal and vertical header information. After changing a data item, the model must emit the headerdatachchanged() signal to notify other components of the change.

2. Resizable model

All types of models can support inserting and deleting rows. Table models and hierarchical models can also support inserting and deleting columns. It is important to notify other components before and after the model dimension changes. Therefore, the following functions may be implemented to allow the model to be resized, but implementations must ensure that appropriate functions are called to notify attached views and delegates:

Function name function
insertRows() Used to add new data rows and items to all types of models. Implementations must call beginInsertRows() before inserting new rows into any underlying data structures, and endInsertRows() immediately thereafter.
removeRows() Used to delete rows and the data items they contain from all types of models. Implementations must call beginRemoveRows() before removing rows from any underlying data structures, and call endRemoveRows() immediately thereafter.
insertColumns() Used to add new columns and data items to table model and hierarchical model. Implementations must call beginInsertColumns() before inserting new columns into any underlying data structures, and endInsertColumns() immediately thereafter.
removeColumns() Used to delete columns and the data items they contain from table model and hierarchical model. Implementations must call beginRemoveColumns() before removing columns from any underlying data structures, and call endRemoveColumns() immediately thereafter.

Typically, these functions should return true if the operation was successful. In some cases, however, the operation may be only partially successful; for example, if fewer than the specified number of rows could be inserted. In this case model should return false to indicate that no add-on can be enabled to handle this case.

The signal emitted by the function called in the implementation of the resize API gives the attached component a chance to take action before any data becomes unavailable. Encapsulating insert and delete operations with begin and end functions also enables the model to properly manage persistent model indexes.

Typically, the begin and end functions are able to notify other components of changes to the model's underlying structure. For more complex changes to the model structure, which may involve internal reorganization, data ordering, or any other structural changes, it is necessary to perform the following sequence:

  • Signal layoutAboutToBeChanged()
  • Updates the internal data representing the model structure.
  • Use changePersistentIndexList() to update persistent indexes
  • Emit the layoutChanged() signal.

This sequence can be used for any structural update in place of more advanced and convenient conservation methods. For example, if a model with 2 million rows needs to remove all odd rows, that's 1 million disjointed ranges, each with 1 element. Using beginRemoveRows and endRemoveRows 1 million times is possible, but it's obviously inefficient. Instead, this can be expressed as a single layout change that updates all necessary persistent indexes at once.

3. Delayed filling of model data

Lazy population of model data effectively allows requests for model information to be delayed until the view actually needs it.

Some models need to fetch data from remote sources, or must perform time-consuming operations to obtain information about how the data is organized. Since views typically request as much information as possible to accurately display model data, it is useful to limit the amount of information returned to the view to reduce unnecessary subsequent data requests.

In a hierarchical model, finding the number of children of a given item is an expensive operation, so it is useful to ensure that the model's rowCount() implementation is only called when necessary. In this case, the hasChildren() function can be reimplemented to provide views with an inexpensive way to check for the presence of children and, in the case of QTreeViews, draw appropriate decorations for their parents.

Regardless of whether the reimplementation of hasChildren() returns true or false, the view may not need to call rowCount() to determine how many children exist. For example, a QTreeView doesn't need to know how many children it has if the parent doesn't expand to show them.

Reimplementing hasChildren() to return true unconditionally is sometimes a useful approach if you know that many items will have children. This ensures that while initially populating the model data as quickly as possible, each item can later be checked for children. The only downside is that items with no children may display incorrectly in some views until the user tries to view non-existing children.

3. Navigation and model index creation

Hierarchical models are required to provide functions that views can call to navigate the tree structure they expose, and to obtain an item's model index.

1. Parents and children

Since the structure exposed to the view is determined by the underlying data structure, each model subclass can create its own model index by providing an implementation of the following functions:

Function name function
index () Given the model index of a parent item, this function allows views and delegates to access the item's children. If no valid child is found—corresponding to the specified row, column, and parent model index—the function must return QModelIndex(), which is an invalid model index.
parent() Provides the model index corresponding to the parent of any given child. If the specified model index corresponds to a top-level item in model, or if there is no valid parent in model, the function must return an invalid model index created with an empty QModelIndex() constructor.

Both of the above functions use the createIndex() factory function to generate indexes for use by other components. model usually provides some unique identifier to this function to ensure that the model index can later be reassociated with its corresponding item.

4. Drag and drop support and MIME type handling

The model / view classes support drag and drop, providing sufficient default behavior for many applications. However, during a drag-and-drop operation, it is also possible to customize how items are coded, whether they are copied or moved by default, and how they are inserted into an existing model.
Also, the specialized behavior that the convenience view class implements should closely match what existing developers expect. The convenience view section provides an overview of this behavior.

1. MIME data

By default, built-in models and views use an internal MIME type (application/x-qabstractitemmodeldatalist) to pass information about the model's index. This specifies data for the item list, containing the row and column numbers for each item, and information about the roles each item supports.
Data encoded using this MIME type can be obtained by calling QAbstractItemModel::mimeData() with a QModelIndexList containing the items to be serialized.
When implementing drag and drop support in a custom model, it is possible to export data items in a special format by reimplementing the following functions:

  • The mimeData()
    function can be reimplemented to return data in other formats than the default application/x-qabstractitemmodeldatalist internal MIME type.
    Subclasses can obtain the default QMimeData object from the base class and add data to it in other formats.

For many models, it is useful to provide item content in a common format represented by MIME types such as text/plain and image/png. Note that images, colors, and HTML documents can be easily added to a QMimeData object using the QMimeData::setImageData(), QMimeData::setColorData(), and QMimeData::setHtml() functions.

2. Accept discarded data

When a drag-and-drop operation is performed on a view, the underlying model is queried to determine what types of operations it supports and what MIME types it can accept. This information is provided by the QAbstractItemModel::supporteddroptions() and QAbstractItemModel::mimeTypes() functions. Models that do not override the implementation provided by QAbstractItemModel support the copy operation and the default internal MIME type of the item.

When serialized item data is dropped into the view, the data will be inserted into the current model using the implementation of QAbstractItemModel::dropMimeData(). The default implementation of this function never overwrites any data in model; instead, it attempts to insert data items as siblings of an item or children of that item.

In order to take advantage of QAbstractItemModel's default implementation of built-in MIME types, new models must provide reimplementations of the following functions:

Function name function
insertrow () insertColumns () These functions enable the model to automatically insert new data using the existing implementation provided by QAbstractItemModel::dropMimeData().
setData () Allows filling new rows and columns with items.
setItemData() This function provides more efficient support for populating new items.

To accept other forms of data, these functions must be reimplemented:

Function name function
supportedDropActions () Combination used to return drag and drop operations, indicating the type of drag and drop operations accepted by the model.
mimetype () 用于返回可由 model 解码和处理的MIME类型列表。通常,支持输入 model 的MIME类型与为外部组件使用的数据编码时可以使用的MIME类型相同。
dropMimeData () 对通过拖放操作传输的数据执行实际解码,确定将在 model 中设置数据的位置,并在必要的地方插入新的行和列。如何在子类中实现此函数取决于每个 model 公开的数据的需求。

如果dropMimeData()函数的实现通过插入或删除行或列来更改 model 的维度,或者如果修改了数据项,则必须注意确保发出所有相关信号。简单地调用子类中其他函数的重新实现,例如setData()、insertRows()和insertColumns(),可以确保 model 的行为一致。
为了确保拖动操作正常工作,重新实现以下从 model 中删除数据的函数是很重要的:
removeRows ()
removeRow ()
removeColumns ()
removeColumn ()
有关使用 item view 拖放的详细信息,请参阅使用 item view 拖放。

3. 方便的 view

方便的 view (QListWidget、QTableWidget和QTreeWidget)覆盖了默认的拖放功能,提供了不那么灵活但更自然的行为,适合于许多应用程序。例如,由于更常见的是将数据放入QTableWidget中的单元格中,用正在传输的数据替换现有的内容,底层 model 将设置目标项的数据,而不是向 model 中插入新的行和列。有关在方便 view 中拖放的详细信息,请参见在项 view 中使用拖放。

5. 针对大量数据的性能优化

canFetchMore()函数检查父节点是否有更多可用数据,并相应地返回true或false。fetchMore()函数根据指定的父节点获取数据。这两个函数可以组合在一起,例如,在涉及增量数据的数据库查询中填充QAbstractItemModel。我们重新实现canFetchMore()来指示是否有更多的数据需要获取,并根据需要将fetchMore()填充到 model 中。
另一个例子是动态填充的树 model ,当树 model 中的分支被扩展时,我们重新实现fetchMore()。
如果fetchMore()的重新实现将行添加到 model 中,则需要调用beginInsertRows()和endInsertRows()。此外,canFetchMore()和fetchMore()都必须重新实现,因为它们的默认实现返回false并且不做任何事情。

七、 model / view 类

这些类使用 model / view 设计模式,在该模式中,底层数据(在 model 中)与用户(在 view 中)呈现和操作数据的方式保持分离。

类名 功能作用
QAbstractItemDelegate 用于显示和编辑 model 中的数据项
QAbstractItemModel item model 类的抽象接口
QAbstractItemView 项 view 类的基本功能
QAbstractListModel 抽象 model ,可以子类化为一维列表 model
QAbstractProxyModel 可以执行排序、过滤或其他数据处理任务的代理项 model 的基类
QAbstractTableModel 抽象 model ,可以被子类化为创建表 model
QColumnView 列 view 的 model / view 实现
QConcatenateTablesProxyModel 代理多个源 model ,连接它们的行
QDataWidgetMapper 数据 model 的一部分到控件之间的映射
QFileSystemModel 本地文件系统的数据 model
QHeaderView 项 view 的标题行或标题列
QIdentityProxyModel 代理未修改的源 model
QItemDelegate 显示和编辑来自 model 的数据项的工具
QItemEditorCreator 使创建 item 编辑器创建基而不子类化QItemEditorCreatorBase成为可能
QItemEditorCreatorBase 在实现新的项编辑器创建器时必须子类化的抽象基类
QItemEditorFactory 用于编辑 view 和委托中的项数据的控件
QItemSelection 管理关于 model 中选定项的信息
QItemSelectionModel 跟踪 view 的选定项
QItemSelectionRange 管理关于 model 中选定项范围的信息
QListView 列表或图标 view 到 model 上
QListWidget 基于 item 的列表控件
QListWidgetItem 项与QListWidget项 view 类一起使用
QModelIndex 用于定位数据 model 中的数据
QPersistentModelIndex 用于定位数据 model 中的数据
QSortFilterProxyModel 持排序和过滤在另一个 model 和 view 之间传递的数据
QStandardItem 项与QStandardItemModel类一起使用
QStandardItemEditorCreator 注册控件的可能性,而不必子类化QItemEditorCreatorBase
QStandardItemModel 用于存储自定义数据的通用 model
QStringListModel 为 view 提供字符串的 model
QStyledItemDelegate 显示和编辑来自 model 的数据项的工具
QTableView 表 view 的默认 model / view 实现
QTableWidget 带有默认 model 的基于项的表 view
QTableWidgetItem Items are used in the QTableWidget class
QTableWidgetSelectionRange Methods for interacting with selections in a model without using the model index and selection model
QTreeView Default model/view implementation for tree view
QTreeWidget A tree view using a predefined tree model
QTreeWidgetItem item for use with the QTreeWidget convenience class
QTreeWidgetItemIterator Method to iterate items in a QTreeWidget instance

Guess you like

Origin blog.csdn.net/qq_43680827/article/details/132225747