35.qt quick-ListView調用C++model類

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
    }
}

效果如下所示:

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章