Qt--自定義Model


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

MVC-image

MVC的好處這里就不多說了,為了開發者使用方便,Qt還提供了基於項(Item)的Model/View實現----QXxxWidget(QTableWidget、QListWidget等),對於一些簡單的應用場景,這已經足夠了並且使用起來非常方便。這里我們簡單介紹下如何使用自定義的數據模型,來滿足各種花式的要求。

1. 選擇合適的Model繼承

1.1 標准數據模型

Qt實現了4類標准數據模型供我們在不同的場景下使用:

  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,作為只讀模型,我們只需要實現以下幾個虛函數:

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

完整代碼見此處


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM