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

I. Overview

Qt includes a set of item view classes that use the model/view architecture to manage the relationship between data and the way it is presented to the user. The features introduced by the architecture provide developers with greater flexibility to customize the presentation, and the framework also provides a standard model interface to allow a wide range of data sources to be used with existing item views.

In this article, we briefly introduce model/view programming concepts, outline the concepts involved, and describe the architecture of the item view system. Each component in the architecture is explained and examples are given of how to use the provided classes. The information referenced here is the official information of Qt.

1.model/view architecture

Model-View-Controller, (Model-View-Controller, MVC) is a design pattern derived from Smalltalk, often used to build user interfaces.

In the book "Design Patterns", Gamma et al write:
MVC consists of three kinds of objects. The model is the application object, the View is its screen display, and the Controller, defines how the user interface reacts to user input.

Before MVC, user interface design tended to keep these objects together. MVC decouples them for flexibility and reusability.

If View and Controller objects are combined, the result is a model / view architecture. This still separates how data is stored from how it is presented to the user, but provides a simpler framework based on the same principles.

This separation makes it possible to display the same data in multiple different Views and to implement new View types without changing the underlying data structures .

In fact, that is to say, if our business can be separated from the interface, it is best to separate it instead of blending it. Just like Linux does not rely on the interface to run, but the Windows system actually blends the system and the interface.

In order to handle user input flexibly, we introduce the concept of delegate.

The benefit of using a delegate in this framework is that it allows customizing how data items are rendered and edited.
insert image description here

The model communicates with data sources and provides interfaces to other components in the architecture. The nature of the communication depends on the type of data source, and how the model is implemented.

View gets model indices from model; these are references to data items . View can retrieve data item from data source by providing model index to model.

In a standard View, the delegate renders the data item. When an item is edited, the delegate communicates directly with the model using the model's index.

It can be seen from the above words that if the model communicates with the delegate and view, it is the index of the model used by the delegate and view.

In general, model/view classes can be divided into the three groups described above: model, view, and delegate.

Each component is defined by an abstract class that provides a common interface and, in some cases, default implementations of functionality.

Abstract classes are intended to be subclassed in order to provide the full set of functionality expected by other components; while also allowing the writing of specialized components.

Model, View and delegate communicate with each other using signals and slots:

  • Signals from the model inform the View about changes to the data held by the data source.
  • Signals from the View provide information about user interaction with the item being displayed.
  • Signals from the delegate are used during editing to tell the model and View about the state of the editor.

2. Model

All item models are based on the QAbstractItemModel class. This class defines an interface that View and delegate use to access data. The data itself does not have to be stored in the model; it can be kept in data structures or repositories provided by separate classes, files, databases, or other application components. This is what separates data. The purpose of the model is a bit like making an intermediate layer to connect with the interface, which needs to be understood.

The model class section will introduce the basic concept of model.

QAbstractItemModel provides a data interface that is flexible enough to handle Views that represent data in the form of tables, lists, and trees.

However, the QAbstractListModel and QAbstractTableModel classes are better starting points when implementing new models for list and table-like data structures , as they provide appropriate default implementations of common functions. These classes can all be subclassed to provide models that support specific types of lists and tables. , I use QAbstractTableModel a lot,

Qt provides some ready-made models to handle data items:

  • QStringListModel is used to store a simple list of QString elements.
  • QStandardItemModel manages a more complex item tree structure, each item can contain arbitrary data.
  • QFileSystemModel provides information about files and directories in the local file system.
  • QSqlQueryModel, qsqlltablemodel and QSqlRelationalTableModel access the database by model / view convention (often used).

If these standard models cannot meet the actual needs, we need to subclass QAbstractListModel, QAbstractListModel or QAbstractTableModel to create our own custom model.

3. View

Qt provides a complete view of different types:

  • QListView displays item list
  • QTableView displays data from the model in the table
  • QTreeView displays data model items in a hierarchical list.

These classes are based on the QAbstractItemView abstract base class. While these classes are ready-made implementations, they can also be subclassed to provide custom Views.
The available Views are described in the View class section.

4. Delegate

QAbstractItemDelegate is the abstract base class for delegates in the model/view framework.

The default delegate implementation is provided by QStyledItemDelegate, which is used as the default delegate by Qt's standard View.

However, QStyledItemDelegate and QItemDelegate are stand-alone alternatives for drawing and provide editors for items in the View . (For this editor, we can use our own custom controls, or Qt controls like QLineEdit, QSpinBox, etc.)

The difference between them is that QStyledItemDelegate uses the current style to paint its items.

Therefore, when implementing a custom delegate or using Qt style sheets, we recommend using QStyledItemDelegate as the base class.

5. Sort

There are two sorting methods in the model/view architecture; which one to choose depends on your underlying model.

If your model is sortable, that is, if it reimplements the QAbstractItemModel::sort() function, both QTableView and QTreeView provide an API that allows you to sort model data programmatically.

In addition, we can also enable interactive sorting (that is, allow the user to sort the data by clicking the View's header), by connecting the QHeaderView::sortIndicatorChanged() signal to the QTableView::sortByColumn() slot function or QTreeView::sortByColumn respectively () slot function.

Alternatively, if your model doesn't have the required interface, or you want to use a List View to display data, use a proxy model to transform the model's structure before displaying the data in the View. This is covered in detail in the section on proxy models.

6. Shortcuts

To benefit applications that rely on Qt's item-based item view and table classes, a number of convenience classes are derived from the standard View class.

They are not intended to be subclassed. Their purpose is to be used.

Examples of these classes include QListWidget, QTreeWidget, and QTableWidget. These classes are not as flexible as the View classes and cannot be used with arbitrary models.

Qt recommends that we use the model/view method to process the data in itemView, unless you really need a set of item-based classes. Indeed, I used the model view programming method, two words to describe: really fragrant!

If you want to take advantage of the features provided by the model/view approach while still using the item-based interface, consider using View classes such as QListView, QTableView, and QTreeView with QStandardItemModel. This means that our view can still use mode/view-based controls, but we use QStandardItemModel to represent each item data in the view. This kind of flexibility is not so high, but Qt still provides it.

2. Use model/view

The next few sections explain how to use the model/view pattern in Qt. Each section contains an example, followed by a section showing how to create new components.

1. Qt contains two models

The two standard models provided by Qt are QStandardItemModel and QFileSystemModel. QStandardItemModel A multipurpose model that can be used to represent various data structures required by list, table and tree views. This model also holds the data item. QFileSystemModel is a model that maintains directory content information. Therefore, it does not hold any data items itself, but simply represents files and directories on the local file system.

QFileSystemModel provides a ready-made model for experimentation that can be easily configured to use existing data. Using this model, we can show how to set up the model for an out-of-the-box view, and explore how to use the model index to manipulate data.

2. Use view in existing model

The QListView and QTreeView classes are the most suitable views for use with QFileSystemModel. The example given below displays the contents of a directory in a tree view, adjacent to the same information in a list view. The two views share the user's selection, so selected items are highlighted in both views.

It's a shared model.
insert image description here

We set up a QFileSystemModel so that it can be used and create some views to display the contents of the directory. This shows the simplest way to use the model. The construction and use of the model is done in a main() function:

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

	QFileSystemModel *model = new QFileSystemModel;
	model->setRootPath(QDir::currentPath());

The model is set up to use data from a file system. Calling setRootPath() tells the model which drive path in the file system to expose to the view.

Create two views to inspect items in the model in two different ways:

QTreeView *tree = new QTreeView(splitter);
tree->setModel(model);
tree->setRootIndex(model->index(QDir::currentPath()));

QListView *list = new QListView(splitter);
list->setModel(model);
list->setRootIndex(model->index(QDir::currentPath()));

view is constructed in the same way as other widgets.
To display the item items in the model in the view, just call its setModel() function with the catalog model as a parameter .

We filter the data provided by the model by calling the setRootIndex() function on each view, passing in an appropriate model index for the current directory from the filesystem model.

The index() function used here is unique to QFileSystemModel. We feed it a directory and it returns a model index. The model index is discussed in the model class.

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

	splitter->setWindowTitle("Two views onto the same file system model");
	splitter->show();
	return app.exec();
}

In the examples above, we ignored how to handle selection of elements. The section Handling selections in the Item view covers this topic in more detail.

3. Model class

1. Basic concepts

In a model/view architecture, the model provides a standard interface that the view and delegate use to access data.

In Qt, the standard interface is defined by the QAbstractItemModel class. Regardless of how data items are stored in any underlying data structure, all subclasses of QAbstractItemModel represent data as a hierarchical structure containing a table of items.

Views use this convention to access data items in the model, but they are not restricted in the way they display information to the user.
insert image description here
The model also notifies any attached views about data changes through the signals and slots mechanism.

This section describes some basic concepts that are critical to the way other components access data items through model classes. Later sections discuss more advanced concepts.

1. model index

In order to ensure that the representation of the data is separated from the way of accessing the data, the concept of model index is introduced. Every piece of information available through a model is represented by a model index. Views and delegates use these indexes to request data items to display.

Therefore, only the model needs to know how to get the data, and it is fairly generic to define the types of data managed by the model. (It doesn’t matter the format of the model fetching data from the outside, but the changed content is limited to the model and will not affect the view. The next time we expand it is actually very nice, and the changes will be smaller.)

The model index contains a pointer to the model that created them, which prevents confusion when using multiple models.

QAbstractItemModel *model = index.model();

A model index provides a temporary reference to a piece of information and can be used to retrieve or modify data through the model. Since the model may reorganize its internal structure from time to time, the model index may become invalid and should not be stored . If a long-term reference to a piece of information is required, a persistent model index must be created. This provides a reference to the information the model keeps up to date.

The temporary model index is provided by the QModelIndex class, and the persistent model index is provided by the QPersistentModelIndex class.

To obtain the model index corresponding to the data item, three attributes must be specified for the model: row number, column number, and the model index of the parent item.

The following sections describe and explain these properties in detail.

2. Rows and columns

In its most basic form, a model can be accessed as a simple table, where items are located by their row and column numbers.

This does not imply that the underlying data blocks are stored in an array structure ; the use of row and column numbers is just a convention to allow components to communicate with each other .

We can retrieve information about any given item's purpose and obtain an index representing that item's purpose by specifying the item's purpose row and column numbers to the model:

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

Models that provide an interface to simple single-level data structures such as lists and tables do not need to provide any additional information, however, as the above code shows, we need to provide more information when obtaining the model index.

insert image description here

The figure above shows a representation of a basic table model where each item is located by a pair of row and column numbers. We obtain a model index referencing a data item by passing the relevant row and column numbers to the model.

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

Top-level items in the model are always referenced by specifying QModelIndex() as their parent item. This will be discussed in the next section.

2. The parent item of the item

The table-like interface provided by the model is ideal when working with data in a table or list view; the row and column numbering system corresponds exactly to the way the view displays items. However, structures like tree views require the model to expose a more flexible interface to the items within it. Therefore, each item can also be the parent of another item, just as 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 item. Outside of the model, the only way to refer to an item object is through the model index, so the parent model index must also be given:

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

insert image description here
The figure above shows a representation of a tree model where each item is referenced by a parent item, row number, and column number.
Item items "A" and "C" are represented as top-level siblings in the model:

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

A item has several child items. The model index of item "B" is obtained by the following code:

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

3. Item roles

Items in the model can perform different roles for other components, allowing different types of data to be provided for different situations.

For example, Qt::DisplayRole is used to access strings that can be displayed as text in a view. Typically, an item contains data in many different roles, the standard role being defined by Qt::ItemDataRole.

We can request item purpose data from the model by passing the model index corresponding to the item purpose to the model and specifying a role to obtain the data type we want:

 QVariant value = model->data(index, role);
insert image description here The role indicates to the model the type of data being referenced. The view can display roles in different ways, so it is important to provide the appropriate information for each role. Some specific uses of roles are covered in more detail in the section Creating a new model.

The most common uses of item data are covered by the standard roles defined in Qt::ItemDataRole. By providing appropriate item data for each role, the model can provide hints to the view and delegate as to how the item should be presented to the user. Different types of views are free to interpret or ignore this information as needed. Additional roles can also be defined for application-specific purposes.

4. Summary

  • The model index provides the model with view and delegate information about the item's destination in a manner independent of any underlying data structures.
  • Items are referenced by their row and column numbers and the model index of their parent item.
  • The model index is constructed by the model upon request from other components such as the view and delegate.
  • If a valid model index is specified for a parent item when an index is requested with index(), the returned index will refer to the item below that parent item in model. The obtained index points to the child item of this item.
  • If an invalid model index is specified for the parent item when requesting an index using index(), the returned index will point to the top-level item in model.
  • The role distinguishes the different types of data associated with the item.

2. Use the Index of the model

To demonstrate how to retrieve data from a model using the model index, we set up a QFileSystemModel without a view and display the names of files and directories in a widget. While this is not the normal way to use models, it demonstrates the conventions model uses when dealing with model indexes.
The loading of QFileSystemModel is asynchronous to minimize system resource usage. We have to take this into account when dealing with this model.
We model the file system in the following way:

QFileSystemModel *model = new QFileSystemModel;
connect(model, &QFileSystemModel::directoryLoaded, [model](const QString &directory) {
    
    
QModelIndex parentIndex = model->index(directory);
int numRows = model->rowCount(parentIndex);
});
model->setRootPath(QDir::currentPath);

In this case, we first set a default QFileSystemModel. We connect it to a lambda that uses the specific implementation of index() provided by the model to get the parent index. In the lambda expression, we use the rowCount() function to count the number of rows in the model. Finally, we set the root path of the QFileSystemModel, let it start loading data and trigger the lambda expression.
For simplicity, we are only interested in the items in the first column of the model. We examine each row in turn, get the first item object model index in each row, and read the item object data stored in the model.

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

To get the model index, we specify the row number, the column number (the first column is 0), and the model index corresponding to the parent element of all the elements we want. The text stored in each item can be obtained through the data() function of the model. We specify the model index and DisplayRole to get the item purpose data in string form.

 QString text = model->data(index, Qt::DisplayRole).toString();
// Display the text in a widget.

}

The above example demonstrates the basic principles of retrieving data from a model:

  • Use rowCount() and columnCount() to get the dimensions of the model. These functions usually require specifying a parent model index.
    -model index is used to access item in model. Specifying item requires row, column, and parent model indexes.
  • To access the top-level elements in the model, use QModelIndex() to specify an empty model index as the parent index.
  • The item item contains data of different roles. To get data for a specific role, the model index and role must be provided to the model.

4. View class

1. Concept

In the model/view architecture, the view fetches data items from the model and presents them to the user.

The representation of the data need not be similar to the data representation provided by the model, and may be quite different from the underlying data structure used to store the data item.

By using the standard model interface provided by QAbstractItemModel and the standard view interface provided by QAbstractItemView, and using the model index to represent the data item in a common way, the separation of content and presentation is realized.

The view generally manages the overall layout of the data obtained from the model. They can render individual data items themselves, or use a delegate to handle rendering and editing functions.

In addition to displaying data, views also handle navigation between items, as well as some aspects of item selection.

These views also implement basic user interface functionality, such as context menus and drag and drop. view can provide default editing function for item, and can also provide custom editor together with delegate.

A view can be constructed without a model, but a model must be provided in order to display useful information. Views keep track of the items selected by the user by using selection items that can be maintained individually for each view or shared between multiple views.

Some views, such as QTableView and QTreeView, display titles and items. These are also implemented by a view class QHeaderView.

Headers usually access the same model as the view that contains them. They get data from the model using the QAbstractItemModel::headerData() function, and usually display header information in the form of labels. New headers can be subclassed from the QHeaderView class to provide more specialized labels for views.

2. Use the view provided by Qt

Qt provides three available view classes, which present the data in the model in a way most users are familiar with. QListView can display the items in the model as a simple list, or in the form of a classic icon view. QTreeView displays the items in the model as a hierarchy of lists, allowing deeply nested structures to be represented in a compact manner. QTableView presents the items in the model in table form, much like the layout of a spreadsheet application.
insert image description here

The default behavior of the standard views shown above should be sufficient for most applications. They provide basic editing functionality and can be customized to suit the needs of a more professional user interface.

1. Use models

We will create a string list model as an example model, set some data in it, and build a view to display the content of the model. This can all be done in one function:

int main(int argc, char *argv[])
{
    
    
QApplication app(argc, argv);

// Unindented for quoting purposes:
QStringList numbers;
numbers << "One" << "Two" << "Three" << "Four" << "Five";

QAbstractItemModel *model = new StringListModel(numbers);

Note that StringListModel is declared as QAbstractItemModel. This means that we can use the model's abstract interface and be sure that the code will still work even if we replace the string list model with a different model. I thought that the QAbstractItemModel interface was used, this is the awesomeness of polymorphism!

The list view provided by QListView is sufficient to display the items in the string list model. We use the following code to build the view and build the model:

QListView *view = new QListView;
view->setModel(model);

view is displayed in the normal way:

	view->show();
	return app.exec();
}

The view renders the content of the model and accesses the data through the model's interface. When the user tries to edit the item, the view uses the default delegate to provide the editor widget.
insert image description here

The figure above shows how QListView represents data in a string list model. Since the model is editable, the view automatically allows each item in the list to be edited using the default delegate.

2. Using multiple views of the model

To provide multiple views for the same model, just set the same model for each view. In the code below, we create two table views, each using the same simple table model we created for this example:

QTableView *firstTableView = new QTableView;
QTableView *secondTableView = new QTableView;

firstTableView->setModel(model);
secondTableView->setModel(model);

Using signals and slots in a model/view architecture means that changes to the model can be propagated to all attached views, ensuring we always have access to the same data, no matter which view is used.
insert image description here

The image above shows two different views of the same model, each containing some selected items. Although data from the model is displayed consistently throughout the view, each view maintains its own internal selection model. This may be useful in some cases, but for many applications a shared selection model is desirable.

3. Selection of Processing Elements

The mechanism for handling selection of elements in a view is provided by the QItemSelectionModel class. All standard views build their own selection models by default and interact with them in the normal way.

The selection model used by the view can be obtained through the selectionModel() function, and the alternative selection model can be specified through setSelectionModel(). The ability to control the selection model used by a view is useful when we want to provide multiple consistent views for the same model data.

In general, unless it is a subclass of model or view, there is no need to directly manipulate the selected content. However, the selection model's interface is also accessible if desired, and we'll discuss how to handle selections in the Item view in Section 12.4.3.

1. Share selection between views

Although it is convenient for the view class to provide its own selection model by default, when we use multiple views on the same model, we usually want the data of the model and the user's selection to be consistent in all views. Since view classes allow replacing their internal selection models, we can achieve uniform selection across views with the following code:

 secondTableView->setSelectionModel(firstTableView->selectionModel());

The second view is the selection model of the first view. Both views now operate on the same selection model, keeping the data and selected item in sync.
insert image description here

In the above example, two views of the same type are used to display data from the same model. However, if two different types of views are used, the selected item items may appear very differently in each view; for example, a continuous selection in a table view may be represented as a set of highlighted item item fragments in a tree view .

5. Delegate class

1. Concept

Unlike the model-view-controller pattern, the model/view design does not include a completely separate component that manages the interaction with the user. Typically, the view is responsible for presenting model data to the user and handling user input. To allow some flexibility in how input is obtained, the interaction is performed by the delegate. These components provide input functionality and are also responsible for rendering individual items in certain views. The standard interface for controlling the delegate is defined in the QAbstractItemDelegate class.

The delegates want to be able to render their own content by implementing the paint() and sizeHint() functions. However, simple widget-based delegates can inherit from QStyledItemDelegate instead of QAbstractItemDelegate and take advantage of the default implementation of these functions.

The delegate editor can manage the editing process by using widgets, or by handling events directly. The first method is described later in this section, and it is also shown in the Spin Box delegate example.

The Pixelator example shows how to create a custom delegate to perform special rendering for the tableview.

2. Use an existing delegate

The standard views provided by Qt use QStyledItemDelegate instances to provide editing functionality. The default implementation of the delegate interface renders elements in the usual style of standard views (QListView, QTableView, and QTreeView).

All standard roles are handled by the default delegate used by standard views. The way they are interpreted is described in the QStyledItemDelegate documentation.

The delegate used by the view is returned by the itemDelegate() function. The setItemDelegate() function allows you to install a custom delegate for a standard view. This function must be used when setting a delegate for a custom view.

3. A simple delegate

The delegate implemented here uses QSpinBox to provide editing functions, mainly for displaying integer models. Although we set up a custom integer-based table model for this, we can easily use QStandardItemModel because the custom delegate controls the data entry. We build a table view to display the contents of the model, which will be edited using a custom delegate.
insert image description here

We inherit the delegate from QStyledItemDelegate because we don't want to write custom display functions. However, we still have to provide functions to manage editor widgets:

class SpinBoxDelegate : public QStyledItemDelegate
{
    
    
	Q_OBJECT
	
public:
	SpinBoxDelegate(QObject *parent = nullptr);
	
	QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
	const QModelIndex &index) const override;
	
	void setEditorData(QWidget *editor, const QModelIndex &index) const override;
	void setModelData(QWidget *editor, QAbstractItemModel *model,
	const QModelIndex &index) const override;
	
	void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
	const QModelIndex &index) const override;
};

Note that the editor widget is not set when the delegate is constructed. We only build editor widgets when needed.

1. Provide an editor

In this example, when the table view needs to provide an editor, it asks the delegate to provide an editor widget appropriate to the item being modified. The createEditor() function provides everything the delegate needs to set up the appropriate widget:

QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
 const QStyleOptionViewItem &/* option */,
 const QModelIndex &/* index */) const
{
    
    
	QSpinBox *editor = new QSpinBox(parent);
	editor->setFrame(false);
	editor->setMinimum(0);
	editor->setMaximum(100);

	return editor;
}

Note that we don't need to keep a pointer to the editor widget, since the view will take care of destroying it when it's no longer needed.

We installed the delegate's default event filter on the editor to ensure it provided the standard editing shortcuts that users expect.

Additional shortcuts can be added to the editor to allow more complex behavior; these are discussed in the section Editing Tips.

The view ensures that the editor's data and geometry information is set up correctly by calling functions we define later for these purposes. We can create different editors based on the model index provided by the view. For example, if we have a column of integers and a column of strings, we can return either a QSpinBox or a QLineEdit, depending on which column is being edited.

The delegate must provide a function to copy the model data into the editor. In this example, we read the data stored in the display role and set the value in the spin box accordingly.

void SpinBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    
    
	int value = index.model()->data(index, Qt::EditRole).toInt();
	
	QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
	spinBox->setValue(value);
}

In this example, we know that the editor widget is a spin box, but we can have different editors for different types of data in the model, in which case we need to set the widget to to the appropriate type.

2. Submit data to the model

When the user finishes editing the value in the spinner, the view will call the setModelData() function, asking the delegate to store the edited value in the model.

void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, 
	 const QModelIndex &index) const
{
    
    
	QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
	spinBox->interpretText();
	int value = spinBox->value();
	
	model->setData(index, value, Qt::EditRole);
}

Since the view manages the editor widget for the delegate, we just need to update the model with the provided editor content. In this example, we make sure the spinner is up to date and update the model with the value it contains using the specified index.

The standard QStyledItemDelegate class notifies the view when it has finished editing by emitting the closeEditor() signal. view ensures that the editor widget is closed and destroyed. In this example, we only provide simple editing functionality, so we never need to emit this signal.

All operations on data are performed through the interface provided by QAbstractItemModel. This makes the delegate largely independent of the type of data it operates on, but in order to use certain types of editor widgets some assumptions must be made. In this example, we assume that the model always contains integer values, but we can still use this delegate for different types of models, since QVariant provides reasonable defaults for unexpected data.

3. Update the geometry of the editor

The delegate's responsibility is to manage the editor's geometry. Geometry must be set when the editor is created, and when the item's object size or position in the view changes. Fortunately, the view provides all the necessary geometric information in the view item object.

void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
 		const QStyleOptionViewItem &option,
		const QModelIndex &/* index */) const
{
    
    
	editor->setGeometry(option.rect);
}

In this example, we only use the geometry information provided by the view item in the item's object rectangle. The delegate that renders an item with multiple elements does not use the item rectangle directly. It will position the editor relative to other elements in the item item.

4. Editing hints

After editing, the delegate should provide hints to other components about the outcome of the editing process and provide hints that facilitate any subsequent editing operations. This is accomplished by sending the closeEditor() signal with the appropriate prompt.

This is handled by the default QStyledItemDelegate event filter, which we installed when building the spin box.

The behavior of the spin box can be tweaked to make it more user-friendly. In the default event filter provided by QStyledItemDelegate, if the user hits Return to confirm their selection in the spinner, the delegate submits the value to the model and closes the spinner.

We can change this behavior by installing our own event filter on the spinner, and provide editing hints as needed; for example, we can send closeEditor() with an EditNextItem hint to automatically start editing the next item in the view .

Another approach that does not require the use of event filters is to provide our own editor widget, possibly subclassing QSpinBox for convenience. This alternative will give us more control over the behavior of the editor widget, at the cost of writing extra code. If you need to customize the behavior of standard Qt Editor widgets, it is usually easier to install event filters in the delegate.

A delegate does not have to issue these prompts, but those that do not are less integrated with the application and are less usable than those that do to support common editing operations.

Guess you like

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