MCV模型

huffscan發表於2017-09-25

有時,我們的系統需要顯示大量資料,比如從資料庫中讀取資料,以自己的方式顯示在自己的應用程式的介面中。早期的 Qt 要實現這個功能,需要定義一個元件,在這個元件中儲存一個資料物件,比如一個列表。我們對這個列表進行查詢、插入等的操作,或者把修改的地方寫回,然後重新整理元件進行顯示。這個思路很簡單,也很清晰,但是對於大型程式,這種設計就顯得蒼白無力。比如,在一個大型系統中,你的資料可能很大,全部存入一個元件的資料物件中,效率會很低,並且這樣的設計也很難在不同元件之間共享資料。如果你要幾個元件共享一個資料物件,要麼你就要用存取函式公開這個資料物件,要麼你就必須把這個資料物件放進不同的元件分別進行維護。

Smalltalk 語言發明了一種嶄新的實現,用來解決這個問題,這就是著名的 MVC 模型。對這個模型無需多言。MVC 是  Model-View-Controller 的簡寫,即模型-檢視-控制器。在 MVC 中,模型負責獲取需要顯示的資料,並且儲存這些資料的修改。每種資料型別都有它自己對應的模型,但是這些模型提供一個相同的 API,用於隱藏內部實現。檢視用於將模型資料顯示給使用者。對於數量很大的資料,或許只顯示一小部分,這樣就能很好的提高效能。控制器是模型和檢視之間的媒介,將使用者的動作解析成對資料的操作,比如查詢資料或者修改資料,然後轉發給模型執行,最後再將模型中需要被顯示的資料直接轉發給檢視進行顯示。MVC 的核心思想是分層,不同的層應用不同的功能。

Qt 4 開始,引入了類似的 model/view 架構來處理資料和麵向終端使用者的顯示之間的關係。當 MVC 的 V 和 C 結合在一起,我們就得到了 model/view 架構。這種架構依然將資料和介面分離,但是框架更為簡單。同樣,這種架構也允許使用不同介面顯示同一資料,也能夠在不改變資料的情況下新增新的顯示介面。為了處理使用者輸入,我們還引入了委託(delegate)。引入委託的好處是,我們能夠自定義資料項的渲染和編輯。

Model View 概覽

Model View 概覽

如上圖所示,模型與資料來源進行互動,為框架中其它元件提供介面。這種互動的本質在於資料來源的型別以及模型的實現方式。檢視從模型獲取模型索引,這種索引就是資料項的引用。通過將這個模型索引反向傳給模型,檢視又可以從資料來源獲取資料。在標準檢視中,委託渲染資料項;在需要編輯資料時,委託使用直接模型索引直接與模型進行互動。

總的來說,model/view 架構將傳統的 MV 模型分為三部分:模型、檢視和委託。每一個元件都由一個抽象類定義,這個抽象類提供了基本的公共介面以及一些預設實現。模型、檢視和委託則使用訊號槽進行互動:

  • 來自模型的訊號通知檢視,其底層維護的資料發生了改變;
  • 來自檢視的訊號提供了有關使用者與介面進行互動的資訊;
  • 來自委託的訊號在使用者編輯資料項時使用,用於告知模型和檢視編輯器的狀態。

所有的模型都是QAbstractItemModel的子類。這個類定義了供檢視和委託訪問資料的介面。模型並不儲存資料本身。這意味著,你可以將資料儲存在一個資料結構中、另外的類中、檔案中、資料庫中,或者其他你所能想到的東西中。我們將在後面再詳細討論這些內容。

QAbstractItemModel提供的介面足夠靈活,足以應付以表格、列表和樹的形式顯示的資料。但是,如果你需要為列表或者表格設計另外的模型,直接繼承QAbstractListModelQAbstractTableModel類可能更好一些,因為這兩個類已經實現了很多通用函式。關於這部分內容,我們也會在後文中詳述。

Qt 內建了許多標準模型:

  • QStringListModel:儲存簡單的字串列表。
  • QStandardItemModel:可以用於樹結構的儲存,提供了層次資料。
  • QFileSystemModel:本地系統的檔案和目錄資訊。
  • QSqlQueryModelQSqlTableModelQSqlRelationalTableModel:存取資料庫資料。

正如上面所說,如果這些標準模型不能滿足你的需要,就必須繼承QAbstractItemModelQAbstractListModel或者QAbstractTableModel,建立自己的模型類。

Qt 還提供了一系列預定義好的檢視:QListView用於顯示列表,QTableView用於顯示錶格,QTreeView用於顯示層次資料。這些類都是QAbstractItemView的子類。這意味著,如果你要建立新的檢視類,則可以繼承QAbstractItemView

QAbstractItemDelegate
則是所有委託的抽象基類。自 Qt 4.4 依賴,預設的委託實現是QStyledItemDelegate。但是,QStyledItemDelegateQItemDelegate都可以作為檢視的編輯器,二者的區別在於,QStyledItemDelegate使用當前樣式進行繪製。在實現自定義委託時,推薦使用QStyledItemDelegate作為基類,或者結合 Qt style sheets。

如果你覺得 model/view 模型過於複雜,或者有很多功能是用不到的,Qt 還有一系列方便使用的類。這些類都是繼承自標準的檢視類,並且繼承了標準模型。這些類並不是為其他類繼承而準備的,只是為了使用方便。它們包括QListWidgetQTreeWidgetQTableWidget。這些類遠不如檢視類靈活,不能使用另外的模型,因此只適用於簡單的情形。


相關文章