Model/View(模型/視圖) 結(jié)構(gòu)是 Qt 中用界面組件顯示與編輯數(shù)據(jù)的一種結(jié)構(gòu),視圖 (View)是顯示和編輯數(shù)據(jù)的界面組件,模型 (Model) 是視圖與原始數(shù)據(jù)之間的接口。
Model/View 結(jié)構(gòu)的典型應(yīng)用是在數(shù)據(jù)庫(kù)應(yīng)用程序中,例如數(shù)據(jù)庫(kù)中的一個(gè)數(shù)據(jù)表可以在一個(gè) OTableView 組件中顯示和編輯。
主要的視圖組件有 QListView、QTreeView 和 QTableView,第 4 章介紹的 QListWidget、QTreeWidget 和 QTableWidget 分別是這 3 個(gè)類的便利類
,它們不使用數(shù)據(jù)模型,而是將數(shù)據(jù)直接存儲(chǔ)在組件的每個(gè)項(xiàng)里。
本章介紹 Model/View 結(jié)構(gòu)原理,包括 QListView、QTreeView、QTableView 視圖組件,以及QStringListModel、QStandardItemModel 等模型類的用法。
Qt中的模型/視圖簡(jiǎn)介和使用(Model/view Programming)是一種框架模式,優(yōu)點(diǎn):
- 在處理較大的數(shù)據(jù)集時(shí)每個(gè)組件各司其職,不至于降低性能;
- 一個(gè)Model可以映射到多個(gè)view,這樣可以以不同的方式查看數(shù)據(jù)同一份數(shù)據(jù);
- 如果底層數(shù)據(jù)源的存儲(chǔ)改變了,我們只需要處理Model就可以了
1 Model/View基本原理
GUI 應(yīng)用程序的一個(gè)很重要的功能是由用戶在界面上編輯和修改數(shù)據(jù),典型的如數(shù)據(jù)庫(kù)應(yīng)用程序。數(shù)據(jù)庫(kù)應(yīng)用程序中,用戶在界面上執(zhí)行各種操作,實(shí)際上是修改了界面組件所關(guān)聯(lián)的數(shù)據(jù)庫(kù)內(nèi)的數(shù)據(jù)。
將界面組件與所編輯的數(shù)據(jù)分離開(kāi)來(lái),又通過(guò)數(shù)據(jù)源的方式連接起來(lái),是處理界面與數(shù)據(jù)的一種較好的方式。Qt 使用 Model/View 結(jié)構(gòu)來(lái)處理這種關(guān)系,Model/View 的基本結(jié)構(gòu)如下圖 所示。其中各部分的功能如下。
- 數(shù)據(jù) (Data)是實(shí)際的數(shù)據(jù),如數(shù)據(jù)庫(kù)的一個(gè)數(shù)據(jù)表或 SQL查詢結(jié)果,內(nèi)存中的一個(gè) StringList,或磁盤(pán)文件結(jié)構(gòu)等
- 視圖或視圖組件 (View) 是屏幕上的界面組件,視圖從數(shù)據(jù)模型獲得每個(gè)數(shù)據(jù)項(xiàng)的模型索引 (model index),通過(guò)模型索引獲取數(shù)據(jù),然后為界面組件提供
顯示數(shù)據(jù)
(當(dāng)只是顯示時(shí)不需要代理)。Qt 提供一些現(xiàn)成的數(shù)據(jù)視圖組件,如QListView、QTreeView 和QTableView 等 - 模型或數(shù)據(jù)模型 (Model) 與實(shí)際數(shù)據(jù)通信,并為視圖組件提供數(shù)據(jù)接口。它從原始數(shù)據(jù)提取需要的內(nèi)容,用于視圖組件進(jìn)行顯示和編輯。Qt 中有一些預(yù)定義的數(shù)據(jù)模型,如QStringListModel 可作為 StringList 的數(shù)據(jù)模型,QSglTableModel 可以作為數(shù)據(jù)庫(kù)中一個(gè)數(shù)據(jù)表的數(shù)據(jù)模型。
由于數(shù)據(jù)源與顯示界面通過(guò) Model/View 結(jié)構(gòu)分離開(kāi)來(lái),因此可以將一個(gè)數(shù)據(jù)模型在不同的視圖中顯示,也可以在不修改數(shù)據(jù)模型的情況下,設(shè)計(jì)特殊的視圖組件。
- 在 Model/View 結(jié)構(gòu)中,還提供了代理 (Delegate) 功能,代理功能可以讓用戶定制數(shù)據(jù)的界面
顯示和編輯方式。
(當(dāng)需要顯示和編輯時(shí)就需要代理)在標(biāo)準(zhǔn)的視圖組件中,代理功能顯示一個(gè)數(shù)據(jù),當(dāng)數(shù)據(jù)被編輯時(shí),代理通過(guò)模型索引與數(shù)據(jù)模型通信,并為編輯數(shù)據(jù)提供一個(gè)編輯器,一般是一個(gè)QLineEdit 組件。
模型、視圖和代理之間使用信號(hào)和槽通信。當(dāng)源數(shù)據(jù)發(fā)生變化時(shí),數(shù)據(jù)模型發(fā)射信號(hào)通知視圖組件;當(dāng)用戶在界面上操作數(shù)據(jù)時(shí),視圖組件發(fā)射信號(hào)表示這些操作信息;當(dāng)編輯數(shù)據(jù)時(shí),代理發(fā)射信號(hào)告知數(shù)據(jù)模型和視圖組件編輯器的狀態(tài)。
2 數(shù)據(jù)模型
所有的基于項(xiàng)數(shù)據(jù)(item data) 的數(shù)據(jù)模型 (Model) 都是基于 QAbstractItemModel 類的,這個(gè)類定義了視圖組件和代理存取數(shù)據(jù)的接口。數(shù)據(jù)無(wú)需存儲(chǔ)在數(shù)據(jù)模型里,數(shù)據(jù)可以是其他類、文件、數(shù)據(jù)庫(kù)或任何數(shù)據(jù)源。Qt 中與數(shù)據(jù)模型相關(guān)的幾個(gè)主要的類的層次結(jié)構(gòu)如下圖 所示。
圖 中的抽象類是不能直接使用的,需要由子類繼承來(lái)實(shí)現(xiàn)一些純虛函數(shù)。Qt 提供了一些模型類用于項(xiàng)數(shù)據(jù)處理,常見(jiàn)的幾個(gè)見(jiàn)下表。
數(shù)據(jù)庫(kù)的3個(gè)模型將在后期進(jìn)行介紹,如果現(xiàn)有的模型類無(wú)法滿足需求,可以從QAbstractItemModel、QAbstractListModel或 QAbstractTableModel 繼承,生成自己定制的數(shù)據(jù)模型類。
3 視圖組件
視圖組件 (View)就是顯示數(shù)據(jù)模型的數(shù)據(jù)的界面組件,Qt 提供的視圖組件如下。
- QListView:用于顯示單列的列表數(shù)據(jù),適用于一維數(shù)據(jù)的操作。
- QTreeView:用于顯示樹(shù)狀結(jié)構(gòu)數(shù)據(jù),適用于樹(shù)狀結(jié)構(gòu)數(shù)據(jù)的操作。
- QTableView:用于顯示表格狀數(shù)據(jù),適用于二維表格型數(shù)據(jù)的操作。
- QColumnView:用多個(gè) QListView 顯示樹(shù)狀層次結(jié)構(gòu),樹(shù)狀結(jié)構(gòu)的一層用一個(gè) OListView顯示。
- QHeaderView:提供行表頭或列表頭的視圖組件,如 QTableView 的行表頭和列表頭。
視圖組件在顯示數(shù)據(jù)時(shí),只需調(diào)用視圖類的 setModel()函數(shù),為視圖組件設(shè)置一個(gè)數(shù)據(jù)模型就可以實(shí)現(xiàn)視圖組件與數(shù)據(jù)模型之間的關(guān)聯(lián),在視圖組件上的修改將自動(dòng)保存到關(guān)聯(lián)的數(shù)據(jù)模型里,一個(gè)數(shù)據(jù)模型可以同時(shí)在多個(gè)視圖組件里顯示數(shù)據(jù)。
前面介紹了QListWidget、QTreeWidget 和 QtableWidget 3 個(gè)可用于數(shù)據(jù)編輯的組件。這3個(gè)類稱為便利類(convenience classes),它們分別是3 個(gè)視圖類的子類,其層次關(guān)系如下圖 所示
用于Model/View結(jié)構(gòu)的幾個(gè)視圖類直接從QAbstractItemView 繼承而來(lái),而便利類則從相應(yīng)的視圖類繼承而來(lái)。
視圖組件類的數(shù)據(jù)采用單獨(dú)的數(shù)據(jù)模型,視圖組件不存儲(chǔ)數(shù)據(jù)。便利類則為組件的每個(gè)節(jié)點(diǎn)或單元格創(chuàng)建一個(gè)項(xiàng)(item),用項(xiàng)存儲(chǔ)數(shù)據(jù)、格式設(shè)置等。所以,便利類沒(méi)有數(shù)據(jù)模型,它實(shí)際上是用項(xiàng)的方式集成了數(shù)據(jù)模型的功能,這樣就將界面與數(shù)據(jù)綁定了。所以,便利類缺乏對(duì)大型數(shù)據(jù)源進(jìn)行靈活處理的能力,適用于小型數(shù)據(jù)的顯示和編輯。
4 代理
代理(Delegate)就是在視圖組件上為編輯數(shù)據(jù)提供編輯器,如在表格組件中編輯一個(gè)單元格的數(shù)據(jù)時(shí),缺省是使用一個(gè) QLineEdit 編輯框。代理負(fù)責(zé)從數(shù)據(jù)模型獲取相應(yīng)的數(shù)據(jù),然后顯示在編輯器里,修改數(shù)據(jù)后,又將其保存到數(shù)據(jù)模型中。
QAbstractItemDelegate 是所有代理類的基類,作為抽象類,它不能直接使用。它的一個(gè)子類QStyledItemDelegate,是 Qt 的視圖組件缺省使用的代理類。
對(duì)于一些特殊的數(shù)據(jù)編輯需求,例如只允許輸入整型數(shù),使用一個(gè) QSpinBox 作為代理組件更恰當(dāng),從列表中選擇數(shù)據(jù)時(shí)使用一個(gè) QComhoBox 作為代理組件更好。這時(shí),就可以從QStyledItemDelegate 繼承創(chuàng)建自定義代理類。
5 Model/View結(jié)構(gòu)的一些概念
5.1 Model/View的基本結(jié)構(gòu)
在 Model/View 結(jié)構(gòu)中,數(shù)據(jù)模型為視圖組件和代理提供存取數(shù)據(jù)的標(biāo)準(zhǔn)接口。在 Qt 中,所有的數(shù)據(jù)模型類都從 QAbstractItemModel 繼承而來(lái),不管底層的數(shù)據(jù)結(jié)構(gòu)是如何組織數(shù)據(jù)的,QAbstractItemModel 的子類都以表格的層次結(jié)構(gòu)表示數(shù)據(jù),視圖組件通過(guò)這種規(guī)則來(lái)存取模型中的數(shù)據(jù),但是表現(xiàn)給用戶的形式不一樣。
下圖是數(shù)據(jù)模型的 3 種常見(jiàn)表現(xiàn)形式。不管數(shù)據(jù)模型的表現(xiàn)形式是怎么樣的,數(shù)據(jù)模型中存儲(chǔ)數(shù)據(jù)的基本單元都是項(xiàng)(item),每個(gè)項(xiàng)有一個(gè)行號(hào)、一個(gè)列號(hào),還有一個(gè)父項(xiàng)(parent item)。在列表和表格模式下,所有的項(xiàng)都有一個(gè)相同的頂層項(xiàng) (root item): 在樹(shù)狀結(jié)構(gòu)中,行號(hào)、列號(hào)、父項(xiàng)稍微復(fù)雜一點(diǎn),但是由這 3 個(gè)參數(shù)完全可以定義一個(gè)項(xiàng)的位置,從而存取項(xiàng)的數(shù)據(jù)。
5.2 模型索引
為了保證數(shù)據(jù)的表示與數(shù)據(jù)存取方式隔離,數(shù)據(jù)模型中引入了模型索引 (model index)的概念。通過(guò)數(shù)據(jù)模型存取的每個(gè)數(shù)據(jù)都有一個(gè)模型索引,視圖組件和代理都通過(guò)模型索引來(lái)獲取數(shù)據(jù)。
OModelIndex 表示模型索引的類。模型索引提供數(shù)據(jù)存取的一個(gè)臨時(shí)指針,用于通過(guò)數(shù)據(jù)模型提取或修改數(shù)據(jù)。因?yàn)槟P蛢?nèi)部組織數(shù)據(jù)的結(jié)構(gòu)隨時(shí)可能改變,所以模型索引是臨時(shí)的。如果需要使用持久性的模型索引,則要使用OPersistentModelIndex 類。
5.3 行號(hào)和列號(hào)
數(shù)據(jù)模型的基本形式是用行和列定義的表格數(shù)據(jù),但這并不意味著底層的數(shù)據(jù)是用二維數(shù)組存儲(chǔ)的,使用行和列只是為了組件之間交互方便的一種規(guī)定。通過(guò)模型索引的行號(hào)和列號(hào)就可以存取數(shù)據(jù)。
要獲得一個(gè)模型索引,必須提供 3 個(gè)參數(shù):行號(hào)、列號(hào)、父項(xiàng)的模型索引。例如,對(duì)于上圖中的Table Model中的3 個(gè)數(shù)據(jù)項(xiàng)A、B、C,獲取其模型索引的代碼是:
QModelIndex indexA = model->index(0,0,QModelIndex());
QModelIndex indexB = model->index(1, 1,QModelIndex());
OModelIndex indexC = model->index(2,1,QModelIndex());
在創(chuàng)建模型索引的函數(shù)中需要傳遞行號(hào)、列號(hào)和父項(xiàng)的模型索引。對(duì)于列表和表格模式的數(shù)據(jù)模型,頂層節(jié)點(diǎn)總是用 QModelIndex()表示。
5.4 父項(xiàng)
當(dāng)數(shù)據(jù)模型是列表或表格時(shí),使用行號(hào)、列號(hào)存儲(chǔ)數(shù)據(jù)比較直觀,所有數(shù)據(jù)項(xiàng)的父項(xiàng)(parent item)就是頂層項(xiàng);當(dāng)數(shù)據(jù)模型是樹(shù)狀結(jié)構(gòu)時(shí),情況比較復(fù)雜(樹(shù)狀結(jié)構(gòu)中,項(xiàng)一般習(xí)慣于稱為節(jié)點(diǎn)),一個(gè)節(jié)點(diǎn)可以有父節(jié)點(diǎn),也可以是其他節(jié)點(diǎn)的父節(jié)點(diǎn),在構(gòu)造數(shù)據(jù)項(xiàng)的模型索引時(shí),必須指定正確的行號(hào)、列號(hào)和父節(jié)點(diǎn)。
上圖中的Tree Model,節(jié)點(diǎn)A 和節(jié)點(diǎn) C的父節(jié)點(diǎn)是頂層節(jié)點(diǎn),獲取模型索引的代碼是:
QModelIndex indexA = model->index(0,0,OModelIndex());
OModelIndex indexC = model->index(2,1,QModelIndex());
但是,節(jié)點(diǎn) B 的父節(jié)點(diǎn)是節(jié)點(diǎn) A,節(jié)點(diǎn) B 的模型索引由下面的代碼生成:
QModelIndex indexB = model->index(1,0,indexA);
5.5 項(xiàng)的角色
在為數(shù)據(jù)模型的一個(gè)項(xiàng)設(shè)置數(shù)據(jù)時(shí),可以賦予其不同項(xiàng)的角色 (item role) 的數(shù)據(jù)。例如,數(shù)據(jù)模型類QStandardItemModel 的項(xiàng)數(shù)據(jù)類是 QStandardItem,其設(shè)置數(shù)據(jù)的函數(shù)是:
void QStandardItem::setData(const QVariant &value,int role= Qt::UserRole + 1)
其中,value 是需要設(shè)置的數(shù)據(jù),role 是設(shè)置數(shù)據(jù)的角色。一個(gè)項(xiàng)可以有不同角色的數(shù)據(jù),用于不同的場(chǎng)合。
role 是 Qt:ItemDataRole 枚舉類型,有多種取值,如 Qt:DisplayRole 角色是在視圖組件中顯示的字符串,Qt:ToolTipRole 是鼠標(biāo)提示消息,Qt.:UserRole 可以自定義數(shù)據(jù)。項(xiàng)的標(biāo)準(zhǔn)角色是Ot::DisplayRole。
在獲取一個(gè)項(xiàng)的數(shù)據(jù)時(shí)也需要指定角色,以獲取不同角色的數(shù)據(jù)。
QVariant QStandardItem::data(int role = Qt::UserRole + 1) const
為一個(gè)項(xiàng)的不同角色定義數(shù)據(jù),可以告知視圖組件和代理組件如何顯示數(shù)據(jù)。例如,在下圖中,項(xiàng)的 DisplayRole 數(shù)據(jù)是顯示的字符串,DecorationRole 是用于裝飾顯示的屬性,TolTipRole定義了鼠標(biāo)提示信息。不同的視圖組件對(duì)各種角色數(shù)據(jù)的解釋和顯示可能不一樣,也可能忽略某些角色的數(shù)據(jù)。
前面已經(jīng)介紹了便利類 QListWidget、QTreeWidget 和 QTableWidget 的使用,后面的文章將介紹 Model/View 結(jié)構(gòu)的基本用法,包括 Qt 預(yù)定義的 QstringListModel、OFileSystemModel、OStandardItemModel以及視圖組件 QListView、QTableView、QTreeView的使用,還介紹如何設(shè)計(jì)和使用自定義代理。涉及數(shù)據(jù)庫(kù)的 Mode/View 的使用將在數(shù)據(jù)庫(kù)一章單獨(dú)介紹。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-582280.html
6. 比較好的Model/View簡(jiǎn)介視頻:Qt 16: 模型/視圖簡(jiǎn)介和使用 (Model/View Programming);Qt 17:模型/視圖編程實(shí)例 (Model/View Programming)(未看);Qt 18 : 模型視圖編程實(shí)例(未看),視頻博主博客地址文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-582280.html
到了這里,關(guān)于05-1_Qt 5.9 C++開(kāi)發(fā)指南_Model/View結(jié)構(gòu)基礎(chǔ)(基本原理;數(shù)據(jù)模型;試圖組件;代理)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!