代碼如下:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QSplitter *splitter = new QSplitter;
QFileSystemModel *model = new QFileSystemModel;
model->setRootPath(QDir::currentPath());
QTreeView *tree = new QTreeView(splitter);
tree->setModel(model);
tree->setRootIndex(model->index(QDir::currentPath()));
QListView *list = new QListView(splitter);
list->setModel(model);
list->setRootIndex(model->index(QDir::currentPath()));
splitter->setWindowTitle("Two views onto the same file system model");
splitter->show();
return app.exec();
}
上面的例子中,我們忽略提及如何處理選擇的項目。下面將詳細講述在視圖中處理所選的項目。
基本概念
在模型/視圖結構中,模型提供了視圖與委託訪問數據的標準接口。在Qt中,標準的接口由QAbstractItemModel類定義。無論多麼數據項被存儲在任何底層的數據結構中,QAbstractItemModel的所有子類所代表的數據作爲包含視圖項的分層結構。視圖使用這個約定來訪問模型中的數據項,但並不限制將該信息傳達給用戶的方式。
Model indexes
爲確保數據被分開被訪問,模型索引的概念被引入。可以通過模型索引來獲得每條信息。視圖與委託使用這些索引來請求顯示的數據項。
因此,模型只需要知道如何獲取數據,並通過模型管理的數據的類型可以被相當普遍定義。型號索引包含一個指向創建它們的模型的指針,在處理多個模型時可以防止混亂。
QAbstractItemModel *model = index.model();
模型索引提供臨時參考信息,並且可以用於通過模型來檢索或修改數據。由於模型可能重組其內部結構,模型的索引可能會變得無效,不宜存儲。如果需要長期參考一條信息,必須創建一個持久性模型索引。這爲模型保持最新信息提供了一個參考。臨時模型索引由QModelIndex類提供,持久性模型索引由QPersistentModelIndex類提供。
取得對應於數據項的模型索引,模型中必須制定三個屬性:一個行號、一個列號,以及父項的模型索引。
行和列
在最基本的形式中,模型可以被一個簡單的表訪問,表項位於行號和列號,這並不意味着底層數據存儲在數據結構中,使用行號和列號只是一個慣例,以允許組件相互通信。我們可以通過指定行號和列號的模型索引有關的任何特定信息,通過下面的方式得到項目的索引:
QModelIndex index = model->index(row, column, ...);
模型提供的接口簡單,單級的數據結構如列表和表格不需要提供任何其他信息。但是,正如上面的代碼所示,當獲得一個模型索引時,我們需要提供更多的信息。
行和列
圖中顯示了一個基本的表模型,其中的每個項目的位置由一對行號和列號表示。我們通過模型索引(一個項目數據)行號和列號來獲取。
QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexB = model->index(1, 1, QModelIndex());
QModelIndex indexC = model->index(2, 1, QModelIndex());
父節點
由模型提供的類似於表的接口給數據項是理想的當在表格或列表視圖中使用數據,行號和列號準確地映射到視圖顯示項目的方式。然而,結構,如樹視圖需要更模型爲項目暴露一個更靈活的接口。因此,每個項目也可以是另一個表的父項,大致相同的方式,在一個樹視圖中的頂級項目可以包含另一個列表項。
當請求的一個模型項的索引時,必須提供有關該項目的父項目的一些信息。在模型外,指定一個項目的唯一途徑是通過一個模型索引,所以父模型索引也必須如下給出:
QModelIndex index = model->index(row, column, parent);
父項,行和列
該圖顯示了一個樹模型,其中每個項目都依賴於由一個父項,一個行號和一個列號。
項目的“A”和“C”表示模型頂層的兄弟姐妹:
項目“A”有很多孩子,可以通過如下方式由“A”索引得到“B”索引:
QModelIndex indexB = model->index(1, 0, indexA);
QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexC = model->index(2, 1, QModelIndex());
項目角色
模型中的項目可以爲其他組件演繹不同的角色,允許爲不同的情況提供不同類型的數據。例如,Qt::DisplayRole可以在用於訪問視圖中被顯示爲文本的字符串。通常情況下,包含數據的項目用於若干不同的角色,且標準角色被Qt::ItemDataRole定義。
我們可以通過模型索引傳遞給相應的項目向模型請求項目數據,並通過指定一個角色來獲取想要的數據類型,如下:
QVariant value = model->data(index, role);
數據類型被稱爲模型的角色指示器。視圖可以以不同的方式顯示角色,因此,爲每個角色提供相應的信息非常重要。
項目數據最常見的用途是覆蓋在Qt::ItemDataRole中定義的標準角色。通過爲每個角色提供相應的項目數據,模型可以爲視圖和委託提供有關項目應如何呈現給用戶的指示,不同的視圖可以根據需要來解釋或忽略此信息。此外,也可以爲應用程序的特定目的而定義附加的角色。
使用模型索引
爲了演示如何將數據從一個模型中進行檢索,使用模型索引,我們創建了一個QFileSystemModel,在窗體上沒有視圖以及顯示文件和目錄的名稱。雖然這並不是使用模型的正常方式,它表明模型在處理模型索引上的約定。
我們用以下述方式構建了一個文件系統模型:
QFileSystemModel *model = new QFileSystemModel;
QModelIndex parentIndex = model->index(QDir::currentPath());
int numRows = model->rowCount(parentIndex);
在這種情況下,我們設置了一個默認QFileSystemModel,由該模型使用index()的特定實現來獲取父索引,使用rowCount()函數來計算行號。
爲簡單起見,我們只關心模型中的第一列中的項目。我們檢查每一行,依次獲取每一行中的第一個項目的模型索引,以及讀出所存儲在該模型項目中的數據。
for (int row = 0; row <<span style=" color:#c0c0c0;"> numRows; ++row) {
QModelIndex index = model->index(row, 0, parentIndex);
爲了獲得一個模型索引,我們指定了行號、列號(第一列爲零),以及所有我們想要的項目的父項目的模型索引。每個項目中的文本檢索可以使用模型的data()函數來獲取。我們指定了模型索引和Qt::DisplayRole來獲取數據項中的字符串。
QString text = model->data(index, Qt::DisplayRole).toString();
// Display the text in a widget.
}
使用模型
我們創建一個字符串列表模型作爲例子,設置一些數據,並構造一個視圖來顯示模型的內容。這都可以在一個單一的函數執行:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QStringList numbers;
numbers << "One" << "Two" << "Three" << "Four" << "Five";
請注意,QStringListModel被聲明爲一個QAbstractItemModel。這使我們能夠爲模型使用抽象接口,並確保代碼仍然有效,即使我們使用不同的模型替換了字符串列表模型。
由而QListView提供的列表視圖足以展示字符串列表模型中的項目。我們構建視圖,並設置模型可以使用下面代碼:
QAbstractItemModel *model = new QStringListModel(numbers);
QListView *view = new QListView;
view->setModel(model);
視圖正常顯示方式
view->show();
return app.exec();
}
視圖展現模型的內容,通過模型的接口訪問數據。當用戶試圖編輯一個項目時,視圖使用缺省代表提供一個編輯器部件。
上面的圖顯示QListView如何使用字符串列表模型表示數據。由於模型可編輯,視圖會自動允許列表中的每個項目使用默認的委託進行編輯。
一個模型的多個視圖
一個模型可以爲多個視圖所使用。在下面的代碼中,我們創建兩個表視圖,使用的均是創建好的同一個模型。
QTableView *firstTableView = new QTableView;
QTableView *secondTableView = new QTableView;
firstTableView->setModel(model);
secondTableView->setModel(model);
在模型/視圖框架中使用信號和槽是指更改模型可以傳遞給所有相連的視圖,以確保始終可以訪問相同的數據,而不管所使用的視圖。
上面的圖顯示了統一模型的兩種不同的視圖,每個都包含了一些選定的項目。儘管模型中的數據在視圖顯示一致,每個視圖維護它自己的內部選擇模型。這在某些情況下有用,但對於許多應用來說,則需要一個共享的選擇模型。
視圖共享選擇
雖然視圖類提供自己的默認選擇模型很方便,但當我們使用多個視圖到同一個模型時,通常需要所有的模型數據和用戶的選擇在所有視圖顯示一致。由於視圖類允許其內部選擇模型進行更換,那麼可以使用如下方式實現視圖之間的統一:
secondTableView->setSelectionModel(firstTableView->selectionModel());
第二個視圖給出了第一個視圖的選擇模型。這兩種視圖現在在同一個選擇模型進行操作,保持了數據和所選項目的同步。
注:
技術在於交流、溝通,轉載請註明出處並保持作品的完整性。