轉載:落葉知秋時數據結構
類QabstractItemModel,QabstractListModel,QAbstractTableModel不保存數據,用戶須要從這些類派生出子類,並在子類中定義某種數據結構來保存數據。app
與此不一樣,類QStandardItemModel負責保存數據,每一個數據項被表示爲類QStandardItem的對象。接下來,咱們主要從兩個方面介紹類QStandardItemMode的內容。函數
首先來看第一方面:性能
如前文所述,一個數據項由若干個『角色,數據子項』對組成。類QStandardItem負責保存、訪問這些數據。該類的內部定義了一個類型爲QVector的容器,字體
每一個容器元素本質上存放一個『角色,數據子項』對。因爲各個角色對應的數據子項可能具備不一樣的類型,Qt使用QVariant來存放每一個數據子項。ui
當用戶但願將一些數據存放在一個QStandardItem對象中時,能夠調用其成員函數:spa
void setData ( const QVariant & value, int role) //將『role, value』對存入。
當用戶但願讀取該對象中的數據時,能夠調用另一個成員函數:.net
QVariant data ( int role = ) const //讀取角色role對應的數據子項。
以上兩個函數是QStandardItem的核心。有了這兩個函數,咱們就能夠訪問該類所表示數據項的任何一個『角色,數據子項』對。然而,對於一些經常使用角色,指針
該類提供了更加簡潔、容易記憶的成員函數。例如,當一個數據項被顯示在視圖中時,它每每包含一些文字、一個圖標,還可能包含一個複選框。code
經常使用角色:
該類提供的一組成員函數能夠方便地訪問這些經常使用角色對應的數據子項:
而後再來看第二方面:
類QStandardItemModel將類QStandardItem表示的數據項組織起來,造成列表、表格、樹甚至更復雜的數據結構。
1:若是數據集被表示爲一個列表,咱們能夠調用類QStandardItemModel的成員函數appendRow()向列表中添加一個數據項,使用item()讀取一個數據項。
如代碼段13-10所示。
行②的構造函數在內部調用該類的setData()函數,將行②的QString對象做爲Qt::DisplayRole對應的數據子項存入新構造的對象。
因爲數據集自己是一個列表,因此咱們使用QListView顯示該數據集,讀者能夠運行該例子查看顯示結果。
代碼段13-10:使用QStandardItemModel處理列表
QStandardItemModel listModel; QStandardItem *rootItem = listModel.invisibleRootItem(); // 行1 for (int row = 0; row < 4; ++row){
QStandardItem *item = new QStandardItem(QString("%1").arg(row) ); // 行2 rootItem->appendRow( item ); //行3 } QListView listView; listView.setModel ( & listModel );
2:若是數據集被表示爲一個表格,能夠調用類QStandardItemModel的成員函數setItem()設定表格中的某個數據項,如代碼段13-11所示。
因爲這個代碼段中的數據集是一個表格,因此使用QTableView顯示該數據集。
代碼段13-11:使用QStandardItemModel處理表格
QStandardItemModel tableModel(4, 4); for (int row = 0; row < 4; ++row){ for (int column = 0; column < 4; ++column) { QStandardItem *item = new QStandardItem(QString("%0,%1").arg(row).arg(column)); tableModel.setItem(row, column, item); } } QTableView tableView; tableView.setModel( & tableModel );
3:若是數據集被表示爲一個樹,能夠調用類QStandardItemModel的成員函數appendRow()向某個樹節點添加子節點。
經過屢次調用該函數,能夠構建一棵複雜的樹。代碼段13-12構建一棵簡單的樹:最頂層的根節點有一個文字內容爲「0」的子節點,
該子節點有一個文字內容爲「1」的子節點。依此類推,「1」子節點有一個「2」子節點,「2」子節點有一個「3」子節點,造成一棵深度爲4的樹。
這棵樹的每一個節點都沒有兄弟節點(具備相同父節點的多個節點被相互稱爲兄弟節點),感興趣的讀者能夠修改這段代碼,以使其中某些節點具備兄弟節點。
因爲數據集是一棵樹,咱們使用QTreeView顯示它。
代碼段13-12,使用QStandardItemModel處理樹:
QStandardItemModel treeModel; QStandardItem *parentItem = treeModel.invisibleRootItem(); for (int i = 0; i < 4; ++i) { QStandardItem *item = new QStandardItem(QString("%0").arg(i)); parentItem->appendRow(item); parentItem = item; } QTreeView treeView; treeView.setModel( & treeModel );
類QStandardItemModel之因此可以表示列表、表格、樹甚至更復雜的數據結構,得益於類QStandardItem在其內部定義了一個類型爲
QVector<QStandardItem*>的容器,能夠將每一個容器元素所指的QStandardItem對象設定爲子對象。表如今如圖13-13所示的類圖上,類QStandardItem和自身具備「children」關係。一個類和自身發生關聯,在UML中被稱爲自關聯(self association)。類QStandardItemModel定義了一個名爲root的數據成員,邏輯上是一個指向QStandardItem對象的指針。這個對象能夠設定多個QStandardItem的對象做爲本身的子對象,而其中每一個子對象又能夠包含其餘的子對象。依此類推,這棵樹能夠具備任意深度,每一個父對象能夠包含任意多個子對象。
很天然地,QStandardItemModel可使用QStandardItem表示具備樹狀數據結構的數據集,如圖13-14所示。
圖中的每一個小方框表示類QStandardItem的一個對象。若是小方框的邊線爲虛,相應的QStandardItem對象並不表示數據集中的任何數據,僅被用來表示某種數據結構。若是小方框的邊線爲實,相應的QStandardItem對象就表示數據集中的一個數據項。在右側的圖中,QStandardItemModel的數據成員root所指的對象表示一個不可見的根,而數據集的根(圖中結點G)被表示爲這個不可見根的一個子節點。
列表被看做一個特殊的樹:不可見根具備若干個子節點,每一個子節點表示列表中的一個數據項,再也不包含任何子節點,如該圖左側所示。
而表格的表示方式反而麻煩一些。不可見根含有若干子節點(圖中A,B,C),這些子節點並不表示數據集中的任何數據項。
第i個子節點會包含若干子節點(好比圖中D,E,F),這些子節點才表示表格第i行的數據項。
最後再討論一下QStandardItemModel表示數據集的優缺點:
使用QStandardItemModel表示數據集具備如下優勢:
然而,這種表示方法也有侷限性:
好比,設數據集是一個1萬行、20列的表格,其中第10列存放的是浮點數。若是咱們想計算這一列的平均值,按照圖13-14,這須要遍歷全部行,
取得第10列的QStandardItem對象,再依據角色「Qt::DisplayRole」取得對應的數據子項。因爲這個數據子項的類型爲QString,還須要將其轉換爲浮點數,
最後求全部浮點數的平均值。這些操做會耗費較長的時間。
所以,對於數據量不是很大、對性能要求不是很高的場合,咱們可使用類QStandardItemModel來表示一個數據集。
不然,用戶應該從QAbstractItemModel、QAbstractListModel或者QAbstractTableModel派生新類,自行管理數據集的存放與訪問。