Qt--自定義Model

衆所周知,Qt提供了一套Model/View框架供開發者使用,Model用來提供數據, View則用來提供視覺層的顯示。實際上這是一套遵循MVC設計模式的GUI框架,由於Qt還提供了默認的Delegate做爲Controller來做爲控制器。html

MVC-image

MVC的好處這裏就很少說了,爲了開發者使用方便,Qt還提供了基於項(Item)的Model/View實現----QXxxWidget(QTableWidget、QListWidget等),對於一些簡單的應用場景,這已經足夠了而且使用起來很是方便。這裏咱們簡單介紹下如何使用自定義的數據模型,來知足各類花式的要求。git

1. 選擇合適的Model繼承

1.1 標準數據模型

Qt實現了4類標準數據模型供咱們在不一樣的場景下使用:github

  1. QStringListModel:存儲字符串列表
  2. QStandardItemModel:存儲樹狀結構的任意數據
  3. QFileSystemModel:存儲本地文件系統上的文件和目錄信息
  4. QSqlQueryModel、QSqlRelationalTableModel、QSqlTableModel:存儲關係型數據庫中的數據

若是使用狀況和上述狀況之一比較類似,則能夠考慮繼承對應的模型類,並從新實現少數虛函數。數據庫

1.2 抽象數據模型

抽象數據模型有3類:設計模式

  1. QAbstractItemModel:項模型,這是全部數據模型的基類。
  2. QAbstractListModel:列表模型,結合QListView使用最合適。
  3. QAbstractTableModel:表模型,結合QTableView使用最合適。

2. 繼承抽象模型

Qt官方提供了完善的文檔來幫助開發者來自定義模型類。根據官網,子類化模型須要開發者實現的功能(即須要從新實現的虛函數)按功能來分能夠分爲三類:數據結構

  • 項數據處理:這又能夠分爲三類----只讀訪問可編輯調整大小
  • 導航和下標建立。
  • 拖拽和MIME類型處理。

咱們只須要按照本身的功能需求來實現其中的一些虛函數。框架

3. 實現一個自定義模型

這裏咱們來實現一個自定義模型,並在QTableView中使用它,所以咱們選擇繼承QAbstractTableModel,這樣咱們須要作的改動最少。但使用QTableModel並不意味着咱們的數據結構就是Table狀的,例以下面的例子中咱們根本不須要內部數據結構。函數

下面咱們要實現這樣一個數據模型:設計

  • 內部不存儲數據結構
  • 表中的每個單元得到的數據是整型,而且值爲列下標的平方
  • 模型中的數據爲只讀

3.1 實現CustomeModel

該模型繼承自QAbstractTableModel,做爲只讀模型,咱們只須要實現如下幾個虛函數:3d

virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual QVariant data(const QModelIndex &index, int role) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
virtual int rowCount(const QModelIndex &parent) const;
virtual int columnCount(const QModelIndex &parent) const;

data()函數與項數據有關,這裏數據有好幾種角色(role),最基本的就是Qt::DisplayRole,這裏爲了實現居中效果,咱們還處理了Qt::TextAlignmentRole角色:

QVariant MyTableModel::data(const QModelIndex &index, int role) const
{
    if (role == Qt::DisplayRole) {
        return index.column() * index.column();
    }
    if (role == Qt::TextAlignmentRole) {
        return Qt::AlignCenter;
    }
    return QVariant();
}

headerData()函數提供表頭數據,包括兩個方向(垂直、水平)的表頭。一樣,這裏的數據也有好幾種角色,咱們只處理Qt::DisplayRole

QVariant MyTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Vertical) {
        if (role == Qt::DisplayRole)    return QVariant("row:" + QString::number(section));
        else                            return QVariant();
    }
    if (orientation == Qt::Horizontal) {
        if (role == Qt::DisplayRole)    return QVariant("column:" + QString::number(section));
        else                            return QVariant();
    }
}

rowCount()columnCount()返回數據模父下標(QModelIndex)的行和列數量,這裏咱們要判別下標是否有效:由於整個表模型的父下標爲無效下標,咱們返回表模型的行列數量;當下標有效時,咱們返回的是父下標指向處的子表的行列

//  if `parent` is invalid, return the whole table row count!
//  else return the children row count of the `parent`
int MyTableModel::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    else
        return 10;
}

3.2 運行結果

result-img

完整代碼見此處

相關文章
相關標籤/搜索