關於 QAbstractItemModel 學習的一點分享
簡介:
Qt的模型、視圖框架對處理一些複雜數據結構的可視化非常有用。
Qt提供了三種常用的數據模型:QAbstractListModel (表單模型)、QAbstractTableModel (表格模型)、QAbstractItemModel (項目模型)。
其中第三種模型最靈活。前兩種模型都是繼承第三種模型的類的。
Qt的幫助文檔裏有提到:
If you need a model to use with an item view such as QML’s List View element or the C++ widgets QListView or QTableView, you should consider subclassing QAbstractListModel or QAbstractTableModel instead of this class.
可以看出,如果是listView 或者 tableView 那麼就考慮前兩種數據模型,但是如果是treeView,那就只好選擇QAbstractItemModel (項目模型)了。
可以這樣理解,QAbstractListModel 是QAbstractTableModel 的特殊化,QAbstractTableModel 是QAbstractItemModel 的特殊化。
接下來,我們着中來理解下QAbstractItemModel類。
關於QAbstractItemModel類的細節描述:
1、QAbstractItemModel 類提供了共模型視圖框架中的其他組件訪問的接口。
2、使用QAbstractItemModel 類,應當子類化。不能直接創建該類的對象。
3、AbstractItemModel 類 支持的 The underlying data model (底層的數據模型)是一個類似hierarchy of tables(有層級關係的表格),如果沒有層級,那就只有rows(行) 和colums(列)。但在AbstractItemModel 類中,還有QModelIndex(索引),這樣,每一個Item 就是一個獨立的表格單元。如下圖:
4、對於每一個數據單元(item of data)可以通過index() 索引,它的子項可以通過sibling()索引,它的父項可以通過parent()索引。
5、對於每一個數據單元都有一些data elements(數據元素)來界定( Qt::ItemDataRole)數據的角色。該數據元素可以通過data()放來來獲取:
如:
QVariant str = item2->data(Qt::ToolTipRole);
qDebug()<<str;
下表列出了數據角色:
什麼是數據角色?可以這樣理解對於每個item呈現給用戶的視角是多方面的,比如:ToolTipRole 角色中的數據是隻有當鼠標移到視圖中多對應的Item纔會顯示。
例如,下圖中選中的Item中 有三個角色,分別是藍色的圖標、字符"B"、提示“”indexB“”。
6、在每一個item中,每個數據角色會對應一個數據,通過setData()方法來爲指定的數據角色設定數據。setItemData()方法 則是爲所有的數據角色設定相同的數據。
7、hasChildren()方法可以確認是否有子項。
8、對於一個層級的表格,都有關於行和列的操作
rowCount() 、columnCount()、 insertRows(), insertColumns(), removeRows(), and removeColumns().
9 、該模型該提供了一些信號來表示數據的變化:dataChanged()、headerDataChanged() 、layoutChanged()
子類化該模型
1、在只讀模型和基本的可編輯模型中,至少需要重寫index(), parent(), rowCount(), columnCount(), data()這些函數。
2、重寫 hasChildren()函數來提供一些特殊的模型的行爲。
3、如果模型是可編輯的,那麼還需要重載setData() 和 flags().
4、重寫headerData()和setHeaderData()對標題進行編輯。
5、在setData()和setHeaderData()函數中必須明確的加載 dataChanged() and headerDataChanged() 信號。
6、對於自定義模型,需要創建模型的索引,這裏會用到createIndex()。
7、模型的重構會用到插入刪除行列insertRows(), removeRows(), insertColumns(),and removeColumns(). 在這些操作中it is important to notify any connected views about changes to the model’s dimensions both before and after they occur:
例如:
bool TreeModel::insertColumns(int position, int columns, const QModelIndex &parent)
{
beginInsertColumns(parent, position, position + columns - 1);
const bool success = rootItem->insertColumns(position, columns);
endInsertColumns();
return success;
}
8、重寫fetchMore() and canFetchMore()使數據模型遞增。
有關子類化的相關實現 可以參考Qt的示例代碼:Simple Tree Model
在Qt的幫助文檔中還有一篇 Model/View Programming 的介紹,該文檔中Model Subclassing Reference 就有提到如何子類化。