Qt的Model/View框架

QT官網(wǎng):Model/View Programming

Qt包含了一系列item view類,它們使用model/view架構(gòu)來管理數(shù)據(jù)及其顯示方式的關(guān)系。模型(model)提供標(biāo)準(zhǔn)接口來存取數(shù)據(jù),視圖(view)定義數(shù)據(jù)的顯示方式。即數(shù)據(jù)的存儲和數(shù)據(jù)的顯示是分開的。


Model


View

model/view架構(gòu)

Model-View-Contoller(MVC,模型-視圖-控制器)是一種設(shè)計(jì)模式,最初源于Smalltalk,經(jīng)常用來構(gòu)建GUI。在設(shè)計(jì)模式中,對MVC的描述如下:

MVC包含3種對象。Model是應(yīng)用對象,View是屏幕的顯示,Controller定義UI對用戶輸入的響應(yīng)方式。在MVC之前,UI管理所有的對象,而MVC把他們進(jìn)行了解耦,提供了更大的靈活性。(數(shù)據(jù)-顯示-控制 進(jìn)行了分離)

如果view和controller合二為一,就變成了Model/View的架構(gòu)。這仍然把數(shù)據(jù)存儲的方式和數(shù)據(jù)顯示的方式進(jìn)行了分離,但提供了基于相同原則的更簡單的框架。這種分離使得在不同的view里顯示相同的數(shù)據(jù)變成可能,以及當(dāng)實(shí)現(xiàn)新的view時(shí)不用改變底層的數(shù)據(jù)結(jié)構(gòu)。為了靈活的處理用戶的輸入,Qt引入了代理(delegate)的概念。

在Qt框架(特別是其模型/視圖編程范式中),模型(models)負(fù)責(zé)存儲和管理數(shù)據(jù),而視圖(views)負(fù)責(zé)數(shù)據(jù)的可視化顯示。代理(delegates)則用于定制視圖中的項(xiàng)目渲染和編輯行為。模型索引是連接這三者的關(guān)鍵,它允許視圖和代理以一致的方式引用模型中的數(shù)據(jù),而無需關(guān)心這些數(shù)據(jù)是如何在模型中存儲的。這種方式使得模型/視圖架構(gòu)非常靈活,可以處理各種不同類型和結(jié)構(gòu)的數(shù)據(jù)。


Qt的Model/View架構(gòu)

model和數(shù)據(jù)源進(jìn)行通信,為其他組件提供接口。通信的本質(zhì)取決于數(shù)據(jù)源的類型以及模型的實(shí)現(xiàn)方式。

view從model中獲取model index,后者提供了對數(shù)據(jù)項(xiàng)的引用。通過向model提供model index,view可以檢索數(shù)據(jù)源中的數(shù)據(jù)項(xiàng)。

在標(biāo)準(zhǔn)視圖中,代理負(fù)責(zé)渲染數(shù)據(jù)項(xiàng)。當(dāng)數(shù)據(jù)項(xiàng)被編輯時(shí),代理會直接使用模型索引(model index)與模型(model)進(jìn)行通信。

通常,如上所述,模型/視圖類可以分為三組:模型(models)、視圖(views)和代理(delegates)。這些組件中的每一個(gè)都由抽象類定義,這些抽象類提供了公共接口,并在某些情況下提供了特性的默認(rèn)實(shí)現(xiàn)。抽象類是為了被繼承以提供其他組件所期望的完整功能集;這也允許編寫專門的組件。

模型、視圖和代理相互之間通過信號和槽進(jìn)行通信:

模型的信號通知視圖關(guān)于數(shù)據(jù)源中數(shù)據(jù)的更改。

視圖的信號提供關(guān)于用戶與正在顯示的項(xiàng)目交互的信息。

代理在編輯過程中使用信號來告訴模型和視圖關(guān)于編輯器狀態(tài)的信息。

基類QAbstractItem*:模型-QAbstractItemModel,視圖-QAbstractItemView,代理-QAbstractItemDelegate.

模型Models

所有的模型類都基于QAbstractItemModel類。該類定義了可以被視圖和代理使用的、訪問數(shù)據(jù)的接口。數(shù)據(jù)本身不必存儲在模型中,數(shù)據(jù)可以存儲在文件、數(shù)據(jù)庫或其他組件中。

QAbstractItemModel提供了訪問數(shù)據(jù)的接口,它為視圖(如表格、列表和樹)展示數(shù)據(jù)提供了足夠的靈活性。然而,當(dāng)為類似列表和表格的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)新模型時(shí),QAbstractListModel?和?QAbstractTableModel?類是更好的起點(diǎn),因?yàn)樗鼈優(yōu)槌R姾瘮?shù)提供了適當(dāng)?shù)哪J(rèn)實(shí)現(xiàn)。這些類中的每一個(gè)都可以被子類化,以提供支持特定類型列表和表格的模型。

Qt提供了一些現(xiàn)成的模型,可以用來處理數(shù)據(jù)項(xiàng):

QStringListModel:用來存儲簡單的QStringList對象。

QStandardItemModel:管理更復(fù)雜的樹形結(jié)構(gòu)的項(xiàng),每個(gè)可以包含任意數(shù)據(jù)。

QFileSystemModel:提供本地文件系統(tǒng)中關(guān)于文件和路徑的信息。

QSqlQueryModel,QSqlTableModel,QSqlRelationalTableModel用于訪問數(shù)據(jù)庫。

如果這些標(biāo)準(zhǔn)的模型不能滿足你的需求,你可以繼承QAbstractItemModel,QAbstractListModel或QAbstractTableModel來創(chuàng)建自己的模型。

視圖Views

完全實(shí)現(xiàn)的類包括:QListView顯示一列項(xiàng), QTableView用表格顯示數(shù)據(jù),QTreeView用層次結(jié)構(gòu)顯示數(shù)據(jù)。上述3類都繼承自QAbstractItemView。這些類可以直接使用,也可以從這些類中派生新的類。

代理Delegates

QAbstractItemDelegate是所有代理的基類。默認(rèn)的實(shí)現(xiàn)的類是QStyledItemDelegete,這是Qt的標(biāo)準(zhǔn)視圖默認(rèn)使用的類。二者的區(qū)別在于,QStyledItemDelegate 使用當(dāng)前樣式表進(jìn)行繪制。在實(shí)現(xiàn)自定義委托時(shí),推薦使用QStyledItemDelegate 作為基類,或者結(jié)合 Qt style sheets。

排序Sorting

在模型/視圖的架構(gòu)下有2種排序,選擇哪種取決于底層的模型。

如果你的模型是可排序的,例如它實(shí)現(xiàn)了QAbstractItemModel::sort()函數(shù),QTableView和QTreeView提供了API允許你通過編程的方式對模型進(jìn)行排序。此外,我們可以使能交互式排序,即運(yùn)行用戶通過點(diǎn)擊視圖的表頭進(jìn)行排序,只要把QHeaderView::sortindicatorChanged()信號連接到QTableView::sortByColumn()槽,和QTreeView::sortByCOlumn()槽。

便捷類

便捷類包括QListWidget,QTreeWidget和QTableWidget。

這些類沒有Views類靈活,不能和model使用。推薦使用view類來處理數(shù)據(jù)。

如果想利用model/view,又想使用item-based接口,可以考慮使用view類,如QListView,QTreeView和QTableView,但和QStandartItemModel一起使用。

使用模型和視圖

下面的內(nèi)容解釋如何在qt中使用模型/視圖的模式。

Qt包含的2中模型

qt提供了2中基本的模型:QStandardItemModel和QFileSystemModel。QStandardItemModel是個(gè)多功能的模型,可用來表示list,table和tree需要的各種類型的數(shù)據(jù)結(jié)構(gòu)。該模型中保持?jǐn)?shù)據(jù)項(xiàng)。

QFileSystemModel用來維護(hù)一個(gè)目錄中內(nèi)容的信息,它不持有任何數(shù)據(jù)項(xiàng),而是僅僅簡單的展示文件系統(tǒng)中文件夾內(nèi)容。

模型類

基本概念

在模型/視圖架構(gòu)中,模型為視圖和代理提供了訪問數(shù)據(jù)的標(biāo)準(zhǔn)接口。在Qt中,標(biāo)準(zhǔn)接口定義在QAbstractItemModel類中。不管底層數(shù)據(jù)項(xiàng)的結(jié)構(gòu)如何, QAbstractItemModel的所有子類用層次結(jié)構(gòu)的方式來展現(xiàn)數(shù)據(jù),包括表格。視圖使用它來訪問模型中的數(shù)據(jù),但和顯示給用戶的信息并不需要嚴(yán)格一致。


三種模型

模型通過信號和槽的機(jī)制通知所有附屬的視圖,數(shù)據(jù)改變了。

模型索引 model index

為了保證數(shù)據(jù)的顯示和數(shù)據(jù)的訪問分離,引入了模型索引的概念。每一片可以通過模型來獲取的信息都被表示成一個(gè)模型索引。視圖和代理通過模型索引來請求被顯示的數(shù)據(jù)。

因此,只有模型需要知道如何獲取數(shù)據(jù),且被模型所管理的數(shù)據(jù)類型可以被定義地非常的通用。模型索引中包含一個(gè)創(chuàng)建他們的模型的指針,當(dāng)多個(gè)模型同時(shí)工作時(shí),不會導(dǎo)致困擾。

QAbstractItemModel *model = index.model();

模型索引提供了對信息的暫時(shí)的引用,還能被用來獲取或修改數(shù)據(jù),但需要通過模型來實(shí)現(xiàn)。由于模型可能隨時(shí)重構(gòu)它內(nèi)部的結(jié)構(gòu),模型索引可能變得無效,因此不應(yīng)該被存儲。如果需要長期引用一條信息,一個(gè)persistent model index(持久模型索引)需要被創(chuàng)建。暫時(shí)的模型索引用QModelIndex類,而持久的模型索引用QPersitentModelIndex類。

想要獲取數(shù)據(jù)項(xiàng)的模型索引,需要項(xiàng)模型提供3個(gè)必要屬性:行號row列號column,和父項(xiàng)的模型索引。

行和列

最基本的形式,模型訪問表格,數(shù)據(jù)項(xiàng)用行號和列號來定位。如下所示:

QModelIndex index = model->index(row, column, ...);


模型索引的獲取

數(shù)據(jù)項(xiàng)的父項(xiàng)(parents of items)

對于樹形結(jié)構(gòu),一個(gè)項(xiàng)還可能是其他項(xiàng)的父項(xiàng)。因此在獲取模型索引時(shí),還要提供父項(xiàng):

QModelIndex index = model->index(row, column, parent);


父項(xiàng)

項(xiàng)的角色(Item Roles)

模型中的數(shù)據(jù)項(xiàng)可以實(shí)現(xiàn)不同的角色,例如Qt::DisplayRule是用來訪問字符串的,在視圖中顯示為text。標(biāo)準(zhǔn)的角色定義在Qt::ItemDataRole中。視圖用不同的方式展示各種角色的數(shù)據(jù),如下圖所示。因此給每個(gè)角色提供合適的信息很重要。

QVariant value = model->data(index, role);


數(shù)據(jù)項(xiàng)的角色

最常用的角色都定義在 Qt::ItemDataRole里。通過提供合適的數(shù)據(jù)給每個(gè)角色,模型可以提供暗示(hint)給視圖和代理,告訴他們應(yīng)該如何把數(shù)據(jù)項(xiàng)展示給用戶。


數(shù)據(jù)的角色

總結(jié):

1.模型索引(Model indexes)為視圖(views)和代理(delegates)提供了關(guān)于模型中項(xiàng)目位置的信息,這種提供信息的方式不依賴于任何底層數(shù)據(jù)結(jié)構(gòu)。

2.數(shù)據(jù)項(xiàng)通過row,column以及他們父對象的索引來定位。

3.模型索引被模型構(gòu)建,當(dāng)視圖和代理需要的時(shí)候。

4.模型索引有父索引。

5.如果給一個(gè)索引提供了一個(gè)invalid的父索引,則表示表示該索引是頂層索引。

6.角色用來區(qū)分一個(gè)item上所包含的不同數(shù)據(jù)。

視圖類

在模型/視圖架構(gòu)中,視圖從模型中獲取數(shù)據(jù)項(xiàng)并展示給用戶看。視圖中展現(xiàn)數(shù)據(jù)的格式可能與數(shù)據(jù)存儲的結(jié)構(gòu)完全不同,這就是模型/視圖的優(yōu)點(diǎn)。

視圖通常用來管理數(shù)據(jù)的布局。視圖可以渲染特定的數(shù)據(jù)項(xiàng),或通過代理來處理渲染和編輯。

除了展示數(shù)據(jù)外,視圖提供在item中導(dǎo)航,以及item的選擇。

視圖構(gòu)建時(shí)可以沒有模型,但想要視圖顯示信息,就必須提供模型。視圖通過使用selections來跟蹤用戶選擇的items,然后每個(gè)視圖維護(hù)各自的選擇,或分享給多個(gè)視圖。

有些視圖,如QTableView和QTreeView除了顯示items,還顯示header(表頭),這是通過另一個(gè)視圖類實(shí)現(xiàn)的,QHeaderView.

使用現(xiàn)成的視圖

Qt提供了3個(gè)現(xiàn)成的視圖:QListView, QTreeView和QTableView。


三種視圖

這三種視圖對絕大多數(shù)應(yīng)用來說是足夠了。


多個(gè)視圖可以共享選擇項(xiàng),如下所示。

secondTableView->setSelectionModel(firstTableView->selectionModel());


共享選擇項(xiàng)

代理類

不同于MVC的模式,模型/視圖結(jié)構(gòu)沒有單獨(dú)的組件來管理用戶的交互。通常,視圖負(fù)責(zé)把模型中的數(shù)據(jù)展示給用戶,并負(fù)責(zé)處理用戶的輸入。為了更靈活的處理用戶的輸入,交互用代理(delegate)來實(shí)現(xiàn)。代理負(fù)責(zé)提供輸入的能力,并且也負(fù)責(zé)數(shù)據(jù)項(xiàng)的渲染。代理的標(biāo)準(zhǔn)接口定義在QAbstractItemDelegate類中。

代理被期望能夠渲染他們的內(nèi)容,通過實(shí)現(xiàn)paint()和sizeHint()函數(shù)。

代理(delegates)中的編輯器可以通過使用控件(widgets)來管理編輯過程,或者直接處理事件來實(shí)現(xiàn)。第一種方法(使用控件)將在本節(jié)的后續(xù)部分中介紹,并且在“SpinBox Delegate”示例中也有所展示。

Pixelator例子展示了如何創(chuàng)建一個(gè)用戶代理來實(shí)現(xiàn)對table view的特定渲染。












1.Qt Model/View框架詳解1_qt modelview-CSDN博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容