QML < 6 > C++ Pass Complex Data Structure to QML TableView uses C++ Model QAbstractTableModel
Preface
TableView tables display commonly used controls and use C++ model s to handle complex data structures and to decouple data and UI.
This article documents Tableview's use of a C++ model example, using Model as the QAbstractTableModel.
Tabular data and styles refer to previous articles: QML>4>Tableview Custom Table Display delegate FontAwesome Canvas
1. QAbstractTableModel class custom CustomDataModel
1 Data format
The data source JSON array format is as follows:
2 Data structure definition
struct Music_Data { bool NewFlag; bool TrendUp; int TrendNum; QString ImageSouce; QString Title; int Time; QString Singer; }; QVector< Music_Data> vDatas;
3 Data structure field corresponding enumeration declaration
Q_ENUMS(EM_DATA_ROLE) enum EM_DATA_ROLE { Data_Role_NewFlag = Qt::UserRole+1, Data_Role_TrendUp, Data_Role_TrendNum, Data_Role_ImageSouce, Data_Role_Title, Data_Role_Time, Data_Role_Singer };
4 Override rowCount
The rowCount function returns the number of rows in the table, coded as follows:
int CustomDataModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); return vDatas.size(); }
5 Override columnCount
The columnCount function returns the number of table columns, which are defined in the QML TableView in this article. The model implements the following functions:
QStringlist head << QStringLiteral("")<< QStringLiteral("Title")<<QStringLiteral("Duration")<< QStringLiteral("singer"); int CustomDataModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent); return head.size(); }
6 Rewrite roleNames
The roleNames function returns a table column, role QML TableView column, that defines the same role and obtains table cell data based on a Role match with the following code:
QHash<int, QByteArray> CustomDataModel::roleNames() const { QHash<int, QByteArray> roles; roles[Data_Role_NewFlag] = "NewFlag"; roles[Data_Role_Title] = "Title"; roles[Data_Role_Time] = "Time"; roles[Data_Role_ImageSouce] = "ImageSouce"; roles[Data_Role_TrendNum] = "TrendNum"; roles[Data_Role_TrendUp] = "TrendUp"; roles[Data_Role_Singer] = "Singer"; return roles; }
7 Rewrite data
The data function is called when the QML TableView updates but with individual data, and the corresponding data is returned from the Role with the following code:
QVariant CustomDataModel::data(const QModelIndex &index, int role) const { if(index.row() >= vDatas.size()) { return QVariant(); } const Music_Data rowData = vDatas.at(index.row()); switch(role) { case Data_Role_NewFlag: { return rowData.NewFlag; }break; case Data_Role_Time: { return rowData.Time; }break; case Data_Role_Title: { return rowData.Title; }break; case Data_Role_Singer: { return rowData.Singer; }break; case Data_Role_ImageSouce: { return rowData.ImageSouce; }break; case Data_Role_TrendNum: { return rowData.TrendNum; }break; case Data_Role_TrendUp: { return rowData.TrendUp; }break; default: return QVariant(); } }
8 Define custom function getDataFromRowByRole
getDataFromRowByRole Gets Role data for specified rows and columns, and custom functions need to add Q_to call function declarations in QML INVOKABLE, code as follows:
Q_INVOKABLE QVariant getDataFromRowByRole(int row ,int role); QVariant CustomDataModel::getDataFromRowByRole(int row, int role) { QVariant data; if(row < vDatas.size()) { Music_Data row_data = vDatas.at(row); switch(role) { case Data_Role_NewFlag:{ data= QVariant::fromValue(row_data.NewFlag);}break; case Data_Role_TrendUp:{ data= QVariant::fromValue(row_data.TrendUp);}break; case Data_Role_TrendNum:{ data= QVariant::fromValue(row_data.TrendNum);}break; case Data_Role_ImageSouce:{ data= QVariant::fromValue(row_data.ImageSouce);}break; case Data_Role_Title:{ data= QVariant::fromValue(row_data.Title);}break; case Data_Role_Time:{ data= QVariant::fromValue(row_data.Time);}break; case Data_Role_Singer:{ data= QVariant::fromValue(row_data.Singer);}break; } } return data; }
2. Model is registered with QML
C++ classes are called in QML and need to be registered with QML. There are two ways to register C++ classes, one is to register class type, the other is to register class instance. This article registers C++ classes as follows:
qmlRegisterType<CustomDataModel>("CustomDataModel",1, 0, "CustomDataModel");
QML is used as follows:
import CustomDataModel 1.0 CustomDataModel { id:tablemodel; }
3. One-to-one correspondence between Model data and TableView columns
TableView does not process data at all, according to Model data. TableView is defined as follows:
TableView { anchors.fill: parent TableViewColumn {title: "NewFlag"; role: "NewFlag"; width: 70 } TableViewColumn {title: "Title"; role: "Title"; width: 70 } TableViewColumn {title: "Time"; role: "Time"; width: 70 } TableViewColumn {title: "ImageSouce"; role: "ImageSouce"; width: 70 } TableViewColumn {title: "TrendNum"; role: "TrendNum"; width: 70 } TableViewColumn {title: "TrendUp"; role: "TrendUp"; width: 70 } TableViewColumn {title: "Singer"; role: "Singer"; width: 70 } model: tablemodel }
The code works as follows:
4. Model column data Role differs from TableView column Role
Call getDataFromRowByRole in QML to get the current table update row data and set the corresponding variable
1 TableView Definition
CustomDataModel { id:tablemodel; } TableView { id:tableview anchors.fill: parent TableViewColumn{role: "NewFlag"; title: ""; width: 80; elideMode: Text.ElideRight;} TableViewColumn{role: "Title"; title: qsTr("Title"); width: 320; elideMode: Text.ElideRight;} TableViewColumn{role: "Time"; title: qsTr("Duration"); width: 90;} TableViewColumn{role: "Singer"; title: qsTr("singer"); width: 120;} headerDelegate:header_delegate itemDelegate: item_delegate rowDelegate: Rectangle { height: styleData.row < 3 ?image_row_height:row_height; //border.color:"gray"; //color: styleData.alternate?"lightgray":"white" } model:tablemodel }
2 rows delegate data
Variable assignment:
property var new_flag : { var data = tablemodel.getDataFromRowByRole(styleData.row,CustomDataModel.Data_Role_NewFlag) return data }
3 Title delegate data
4-hour delegate data
5 singer delegate data
6 Running effect
summary
1 json data parsing
void CustomDataModel::parseJsonData() { const QString filepath = ":/data/music_data.json"; QFile file(filepath); if(!file.exists()) { return ; } if(!file.open(QFile::ReadOnly)) { return; } QByteArray jsonstr = file.readAll(); QJsonParseError parseerror; QJsonDocument doc = QJsonDocument::fromJson(jsonstr,&parseerror); if(parseerror.error != QJsonParseError::NoError) { qDebug() <<"parseerror"; return; } QJsonObject obj = doc.object(); QJsonArray data = obj["Data"].toArray(); foreach(auto item , data) { Music_Data data; data.Time =item["Time"].toInt() ; data.NewFlag= item["NewFlag"].toBool(); data.TrendUp=item["TrendUp"].toBool(); data.TrendNum=item["TrendNum"].toInt(); data.ImageSouce=item["ImageSouce"].toString(); data.Singer=item["Singer"].toString(); data.Title=item["Title"].toString(); vDatas.push_back(data); } }
2 Custom model Crater
Do not implement a custom model, it will result in a data function
Without calling, the QAbstractItemModel functions selected by the base class at the beginning must be implemented. The code for not calling the data function after the implementation is posted here, and the reason will be analyzed later.
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const ; QModelIndex CustomDataModel::index(int row, int column, const QModelIndex &parent) const { return QModelIndex(); }
virtual QModelIndex parent(const QModelIndex &child) const ; QModelIndex CustomDataModel::parent(const QModelIndex &child) const { Q_UNUSED(child); return QModelIndex(); }