QT ViewModel model learning

Separating the interface components from the edited data and connecting them through the data source is a better way to deal with the interface and data. Qt uses the Model/View structure to handle this relationship. The basic structure of Model/View is shown in the figure.

The functions of each part are as follows:

  • Data (Data) is the actual data, such as a data table of the database or the result of an SQL query, a StringList in memory, or a disk file structure, etc.

  • A view or view component (View) is an interface component on the screen. The view obtains the model index of each data item from the data model, obtains the data through the model index, and then provides display data for the interface component. Qt provides some ready-made data view components, such as QListView, QTreeView and QTableView.

  • The model or data model (Model) communicates with the actual data and provides the data interface for the view components. It extracts the required content from the raw data for display and editing by the view component. There are some predefined data models in Qt, such as QStringListModel can be used as the data model of StringList, QSqlTableModel can be used as the data model of a data table in the database.

Since the data source and the display interface are separated by the Model/View structure, a data model can be displayed in different views, or special view components can be designed without modifying the data model.
In the Model/View structure, a Delegate function is also provided. The Delegate function allows users to customize the interface display and editing methods of data. In a standard view component, the proxy function displays a data, and when the data is edited, the proxy communicates with the data model through the model index and provides an editor for editing the data, usually a QLineEdit component.
Signals and slots are used for communication between models, views and delegates. When the source data changes, the data model emits a signal to notify the view component; when the user operates the data on the interface, the view component emits a signal to represent the operation information; when the data is edited, the proxy emits a signal to inform the data model and the view component editor. state.

data model

Based on the QAbstractltemModel class, this class defines the interface for view components and delegates to access data. The data does not need to be stored in the data model, the data can be other classes, files, databases or any data source.

view component

The view component (View) is the interface component that displays the data of the data model. The view components provided by Qt are as follows:

  • QListView: used to display single-column list data, suitable for one-dimensional data operations.

  • QTreeView: used to display tree structure data, suitable for tree structure data operations.

  • QTableView: used to display tabular data, suitable for operations on two-dimensional tabular data.

  • QColumnView: Displays a tree-like hierarchy with multiple QListViews, and one level of the tree-like structure is displayed with one QListView.

  • QHeaderView: View components that provide row headers or list headers, such as the row header and column header of QTableView.

Delegate

The proxy is to provide an editor on the view component for editing data

model index

In order to ensure the isolation of data representation and data access, the concept of model index is introduced into the data model. Each data accessed through the data model has a model index, and both view components and proxies obtain data through the model index.

QModelIndex Class representing the model index. The model index provides a temporary pointer to data access for extracting or modifying data through the data model. Model indexes are temporary because the structure of how data is organized inside a model can change at any time. If you need to use a persistent model index, use the QPersistentModelIndex class.

row and column numbers

The basic form of the data model is tabular data defined by rows and columns, but this does not mean that the underlying data is stored in two-dimensional arrays. The use of rows and columns is just a provision for the convenience of interaction between components. Data can be accessed through the row and column numbers of the model index.

To get a model index, 3 parameters must be provided: row number, column number, the model index of the parent. For example, for 3 data items A, B, C in the tabular data model in Figure 5, the code to get the model index is:

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

In the function that creates the model index, you need to pass the row number, column number, and the model index of the parent item. For list and table mode data models, the top-level node is always represented by QModelIndex().

parent

When the data model is a list or table, it is more intuitive to use row numbers and column numbers to store data, and the parent of all data items is the top-level item; when the data model is a tree structure, the situation is more complicated (in a tree structure, the items are generally Used to be called a node), a node can have a parent node, and can also be the parent node of other nodes. When constructing the model index of the data item, the correct row number, column number and parent node must be specified.

For the tree-like data model in Figure 5, the parent nodes of Node A and Node C are the top-level nodes, and the code to get the model index is:

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

However, node B's parent is node A, and node B's model index is generated by the following code:

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

the role of the item

When setting data for one item of a data model, data that can be assigned roles for different items. For example, the item data class of the data model class QStandardItemModel is QStandardItem, and its function to set the data is:

void QStandardItem::setData(const QVariant &value, int role= Qt::UserRole + 1)

Among them, value is the data to be set, and role is the role to set the data. An item can have data for different roles, used in different situations.

role is the Qt::ItemDataRole enumeration type and has multiple values. For example, Qt::DisplayRole is the string displayed in the view component, Qt::ToolTipRole is the mouse prompt message, and Qt::UserRole can customize data. The standard role for an item is Qt::DisplayRole.

You also need to specify roles when getting data for an item to get data for different roles:

QVariant QStandardItem::data(int role = Qt::UserRole + 1) const

Defining data for the different roles of an item tells the view and delegate components how to display the data.

example:

Model class:

class MemberModel : public QAbstractListModel

{
Q_OBJECT
public:
explicit MemberModel(QObject *parent = 0);
~MemberModel();
virtual QVariant data(const QModelIndex &index, int role) const;  //Used to get data role can be customized
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);  //Edit data
static void  sortFn(const QModelIndex& source_left, const QModelIndex& source_right, bool& ret); //list sorting function
};



#define MEMBER_ROLE_DATA        Qt::UserRole + 1
QVariant MemberModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
T_MemberList info = m_memberList.at(index.row());
if (role == MEMBER_ROLE_DATA)
{
return QVariant::fromValue(info);
}
}

QListView set model

MemberModel*   m_pMemberModel= new MemberModel(this);
ProxyModel* m_ProxyModel;
m_ProxyModel = new ProxyModel(this);
m_ProxyModel->sort(0);
m_ProxyModel->setSourceModel(m_pMemberModel);
m_ProxyModel->setCompareFn(MemberModel::sortFn);
ui.listView->setModel(m_ProxyModel);

Delegate class:

Events such as item drawing and clicking of QListView can be completed in the paint and editorEvent events in the Delegate class

Class MemberDelegate : public QStyledItemDelegate
{

    Q_OBJECT
public:
    MemberDelegate (QObject * parent=0);
   ~MemberDelegate ();
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
    virtual QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const;

}

void MemberDelegate ::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    //Get data through the model data function
    T_MemberList info = index.data(MEMBER_ROLE_DATA).value<T_MemberList>();
    painter->save();
    //draw selected state
    if (itemOption.state & QStyle::State_HasFocus)
    {
        painter->fillRect(rect, QColor("#e8e8e8"));
      //itemOption.state = itemOption.state ^ QStyle::State_HasFocus;
    }
    else if (itemOption.state & QStyle::State_MouseOver)
    {
        painter->fillRect(rect, QColor("#f2f2f2"));
    }
    else
        painter->fillRect(rect, QColor("#ffffff"));
    ...

   painter->restore();

}

QListView set Delegate

MemberDelegate* m_pMemberDelegate;
m_pMemberDelegate = new MemberDelegate(this);
ui.listView->setItemDelegate(m_pMemberDelegate);

 

Tags: Qt

Posted by bschultz on Fri, 20 May 2022 02:01:21 +0300