35.qt quick-ListView呼叫C++model類
阿新 • • 發佈:2021-07-02
ListView中的model可以使用c++中繼承自QAbstractItemModel或QAbstractListModel的自定義模型類
所以本章主要學習如何使用C++中的繼承QAbstractListModel的model類.
1.QAbstractListModel介紹
QAbstractListModel為模型提供了一個標準介面,它不能被直接使用,我們必須子類化實現它.
如果你想用於樹檢視,則使用子類QAbstractTableModel可能更合適。
在對QAbstractListModel進行子分類時,必須重寫:
int rowCount(const QModelIndex &parent = QModelIndex());//返回顯示的行數 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole); //返回index單元格下的role角色資料。通過index可以獲取行號和列號 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole); //返回標題role角色對應的值(需要標題資料時重寫) // section:段號,從0開始,對於Qt::Horizontal水平標題,則是每列的標題名,對於Qt::Vertical垂直標題,則是每行的左側標題名//orientation:標題型別 //role:對應值是Qt:: ItemDataRole列舉, 對於role角色,常用的有: //Qt::DisplayRole :以文字方式顯示資料(QString) //Qt::DecorationRole :將資料作為圖示來裝飾(QIcon,QPixmap) //Qt::EditRole :可編輯的資料資訊顯示(QString) //Qt::ToolTipRole :作為工具提示顯示(QString) //Qt::StatusTipRole :作為狀態列中顯示的資料(QString) //Qt::WhatsThisRole :作為幫助資訊欄中顯示的資料(QString) //Qt::FontRole :設定字型(QFont)//Qt::TextAlignmentRole :設定模型資料的文字對齊(Qt::AlignmentFlag) //Qt::BackgroundRole :設定模型資料的背景色(QBrush) //Qt::ForegroundRole : 設定模型資料的前景色,比如字型(QBrush) //Qt::SizeHintRole : 設定模型資料的大小 //Qt::UserRole : 用來儲存使用者角色的資料,每一個單元格資料(很多)較為複雜時使用,可以通過Qt::UserRole、Qt::UserRole + 1、Qt::UserRole + 2等來設定資料 // 使用Qt::UserRole時,我們還需要重新重寫roleNames()函式,需要返回一個QHash類,表示每個Qt::UserRole+N對應的是角色叫什麼名字.
對於可編輯列表模型,您還必須提供:
Qt::ItemFlags QAbstractListModel::flags(const QModelIndex &index) ; //設定每個單元格的flag,對於可編輯模型,必須重寫它,新增Qt::ItemIsEditable(可編輯屬性) //然後當我們雙擊時,會預設建立一個編輯元件(這是由 delegate 完成的)然後delegate會呼叫QAbstractTableModel ::data(index, Qt::EditRole)讀取預設編輯值 //當我們編輯完成後, delegate會呼叫QAbstractTableModel :: setData (index, value, Qt::EditRole)告訴我們是否儲存資料. bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); //將index單元格下的role角色設定為value //對於可編輯模型,必須重寫該函式,然後還需要重寫flags() //返回值為true:表示設定成功,然後還需要顯式發射dataChanged訊號
如果對於可調整行的模型,可以重寫insertRows()、removeRows()、在實現這些函式時,還需要呼叫合適的父類函式,用來通知model調整了哪些內容:
insertRows(): //在向資料結構插入新行之前需要呼叫父類的beginInsertRows(),並且必須在之後立即呼叫endInsertRows()。 RemoveRows(): //在刪除行之前需要呼叫父類的beginRemoveRows(),並且必須在之後立即呼叫endRemoveRows()。
注意:如果要重新重新整理model資料,則必須在重新整理model之前呼叫beginResetModel(),然後重新整理之後呼叫endResetModel。
或者在重新整理之後,emit dataChanged(index(0,0),index(rowCount,columnCount))來進行重新整理檢視
- 如果想要實現QML呼叫C++中的某個角色的值,那麼我們必須重寫roleNames()函式.
- 然後當我們在QML中獲取某個角色的值時,會自動通過roleNames()函式返回的QHash類轉換成一個Qt::UserRole+N.
- 然後model會自動呼叫data(const QModelIndex &index, Qt::UserRole+N)來獲取值返回給QML
2.C++標頭檔案如下所示
#ifndef CUSTOMMODEL_H #define CUSTOMMODEL_H #include <QAbstractListModel> // model中的資料 class CustomModelPrivate { public: CustomModelPrivate(); void clear(); void update(); QList<QVector<QString> * > m_data; QHash<int, QByteArray> m_role; // 每個m_data[i]中的使用者角色 int m_rowCnt; }; class CustomModel : public QAbstractListModel { Q_OBJECT public: explicit CustomModel(QAbstractListModel *parent = nullptr); int rowCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; QHash<int, QByteArray> roleNames() const; signals: private: CustomModelPrivate *m_dataPtr; }; #endif // CUSTOMMODEL_H
3.C++原始檔如下所示
#include "custommodel.h" #include <QDateTime> #include <QDebug> CustomModelPrivate::CustomModelPrivate() { m_role.insert(Qt::UserRole+0, "number"); // 第1個角色名 m_role.insert(Qt::UserRole+1, "dev"); // 第2個角色名 m_role.insert(Qt::UserRole+2, "status"); // 第3個角色名 m_role.insert(Qt::UserRole+3, "date"); // 第4個角色名 m_rowCnt =10; update(); } void CustomModelPrivate::clear() { int count = m_data.size(); if(count > 0) { for(int i = 0; i < count; i++) { delete m_data.at(i); } m_data.clear(); } } void CustomModelPrivate::update() { for (int i = 0; i < m_rowCnt; i++) { QVector<QString>* line = new QVector<QString>(5); // 每行model中建立5條使用者資料 line->replace(0,QString("%1").arg(i+1)); line->replace(1,"顯示器"); line->replace(2,qrand()%2 == 0 ? "顯示" : "未顯示"); line->replace(3,QDateTime::currentDateTime().addDays(-10).toString("hh:mm:ss")); m_data.append(line); } } CustomModel::CustomModel(QAbstractListModel *parent) : QAbstractListModel(parent) { m_dataPtr = new CustomModelPrivate(); } QVariant CustomModel::data(const QModelIndex &index, int role) const { if (role >= Qt::UserRole) { //顯示內容 return m_dataPtr->m_data[index.row()]->at(role - Qt::UserRole); } return QVariant(); } int CustomModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) //由於parent未使用,所以通過Q_UNUSED去掉編譯警告 return m_dataPtr->m_rowCnt; } QHash<int, QByteArray> CustomModel::roleNames() const { return m_dataPtr->m_role; }
然後在main.cpp中註冊類:
qmlRegisterType<CustomModel>("Model",1,0,"CustomModel");
4.最後main.qml如下所示
import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 2.5 import Model 1.0 Window { id: wind visible: true width: 500 height: 400 Component { id: fruitDelegate Rectangle { id: rect border.width: 0.5 border.color: "#666" color: rect.ListView.isCurrentItem ? "#AACCCCCC" : "transparent" width: wind.width height: 100 Column { spacing: 4 anchors.verticalCenter: parent.verticalCenter leftPadding: 20 Text { text: dev + number font.pixelSize: 15 font.family: "Microsoft Yahei" color: "#1F8ABF" } Text { text: "狀態: "+ status font.pixelSize: 15 font.family: "Microsoft Yahei" color: status.indexOf("未顯示") >=0 ? "#FF5A47" : "#1F8ABF" } Text { text: "時間: "+ date font.pixelSize: 15 font.family: "Microsoft Yahei" color: "#1F8ABF" } } MouseArea { anchors.fill: parent onClicked: rect.ListView.view.currentIndex = index } } } ListView { anchors.fill: parent model: CustomModel { id : model } delegate: fruitDelegate focus: true } }
效果如下所示: