#(41):model/view 架構
有時,我們的系統需要顯示大量數據,比如從數據庫中讀取數據,以自己的方式顯示在自己的應用程序的界面中。早期的 Qt 要實現這個功能,需要定義一個組件,在這個組件中保存一個數據對象,比如一個列表。我們對這個列表進行查找、插入等的操作,或者把修改的地方寫回,然后刷新組件進行顯示。這個思路很簡單,也很清晰,但是對于大型程序,這種設計就顯得蒼白無力。比如,在一個大型系統中,你的數據可能很大,全部存入一個組件的數據對象中,效率會很低,并且這樣的設計也很難在不同組件之間共享數據。如果你要幾個組件共享一個數據對象,要么你就要用存取函數公開這個數據對象,要么你就必須把這個數據對象放進不同的組件分別進行維護。
Smalltalk 語言發明了一種嶄新的實現,用來解決這個問題,這就是著名的 MVC 模型。對這個模型無需多言。MVC 是 ?Model-View-Controller 的簡寫,即模型-視圖-控制器。在 MVC 中,模型負責獲取需要顯示的數據,并且存儲這些數據的修改。每種數據類型都有它自己對應的模型,但是這些模型提供一個相同的 API,用于隱藏內部實現。視圖用于將模型數據顯示給用戶。對于數量很大的數據,或許只顯示一小部分,這樣就能很好的提高性能。控制器是模型和視圖之間的媒介,將用戶的動作解析成對數據的操作,比如查找數據或者修改數據,然后轉發給模型執行,最后再將模型中需要被顯示的數據直接轉發給視圖進行顯示。MVC 的核心思想是分層,不同的層應用不同的功能。
Qt 4 開始,引入了類似的 model/view 架構來處理數據和面向最終用戶的顯示之間的關系。當 MVC 的 V 和 C 結合在一起,我們就得到了?model/view 架構。這種架構依然將數據和界面分離,但是框架更為簡單。同樣,這種架構也允許使用不同界面顯示同一數據,也能夠在不改變數據的情況下添加新的顯示界面。為了處理用戶輸入,我們還引入了委托(delegate)。引入委托的好處是,我們能夠自定義數據項的渲染和編輯。
[](http://files.devbean.net/images/2013/01/model-view-overview.png)
Model View 概覽
如上圖所示,模型與數據源進行交互,為框架中其它組件提供接口。這種交互的本質在于數據源的類型以及模型的實現方式。視圖從模型獲取模型索引,這種索引就是數據項的引用。通過將這個模型索引反向傳給模型,視圖又可以從數據源獲取數據。在標準視圖中,委托渲染數據項;在需要編輯數據時,委托使用直接模型索引直接與模型進行交互。
總的來說,model/view 架構將傳統的 MV 模型分為三部分:模型、視圖和委托。每一個組件都由一個抽象類定義,這個抽象類提供了基本的公共接口以及一些默認實現。模型、視圖和委托則使用信號槽進行交互:
* 來自模型的信號通知視圖,其底層維護的數據發生了改變;
* 來自視圖的信號提供了有關用戶與界面進行交互的信息;
* 來自委托的信號在用戶編輯數據項時使用,用于告知模型和視圖編輯器的狀態。
所有的模型都是`QAbstractItemModel`的子類。這個類定義了供視圖和委托訪問數據的接口。模型并不存儲數據本身。這意味著,你可以將數據存儲在一個數據結構中、另外的類中、文件中、數據庫中,或者其他你所能想到的東西中。我們將在后面再詳細討論這些內容。
`QAbstractItemModel`提供的接口足夠靈活,足以應付以表格、列表和樹的形式顯示的數據。但是,如果你需要為列表或者表格設計另外的模型,直接繼承`QAbstractListModel`和`QAbstractTableModel`類可能更好一些,因為這兩個類已經實現了很多通用函數。關于這部分內容,我們也會在后文中詳述。
Qt 內置了許多標準模型:
* `QStringListModel`:存儲簡單的字符串列表。
* `QStandardItemModel`:可以用于樹結構的存儲,提供了層次數據。
* `QFileSystemModel`:本地系統的文件和目錄信息。
* `QSqlQueryModel`、`QSqlTableModel`和`QSqlRelationalTableModel`:存取數據庫數據。
正如上面所說,如果這些標準模型不能滿足你的需要,就必須繼承`QAbstractItemModel`、`QAbstractListModel`或者`QAbstractTableModel`,創建自己的模型類。
Qt 還提供了一系列預定義好的視圖:`QListView`用于顯示列表,`QTableView`用于顯示表格,`QTreeView`用于顯示層次數據。這些類都是`QAbstractItemView`的子類。這意味著,如果你要創建新的視圖類,則可以繼承`QAbstractItemView`。
`
QAbstractItemDelegate`則是所有委托的抽象基類。自 Qt 4.4 依賴,默認的委托實現是`QStyledItemDelegate`。但是,`QStyledItemDelegate`和`QItemDelegate`都可以作為視圖的編輯器,二者的區別在于,`QStyledItemDelegate`使用當前樣式進行繪制。在實現自定義委托時,推薦使用`QStyledItemDelegate`作為基類,或者結合 Qt style sheets。
如果你覺得 model/view 模型過于復雜,或者有很多功能是用不到的,Qt 還有一系列方便使用的類。這些類都是繼承自標準的視圖類,并且繼承了標準模型。這些類并不是為其他類繼承而準備的,只是為了使用方便。它們包括`QListWidget`、`QTreeWidget`和`QTableWidget`。這些類遠不如視圖類靈活,不能使用另外的模型,因此只適用于簡單的情形。
- (1)序
- (2)Qt 簡介
- (3)Hello, world!
- (4)信號槽
- (5)自定義信號槽
- (6)Qt 模塊簡介
- (7)MainWindow 簡介
- (8)添加動作
- (9)資源文件
- (10)對象模型
- (11)布局管理器
- (12)菜單欄、工具欄和狀態欄
- (13)對話框簡介
- (14)對話框數據傳遞
- (15)標準對話框 QMessageBox
- (16)深入 Qt5 信號槽新語法
- (17)文件對話框
- (18)事件
- (19)事件的接受與忽略
- (21)事件過濾器
- (22)事件總結
- (23)自定義事件
- (24)Qt 繪制系統簡介
- (25)畫刷和畫筆
- (26)反走樣
- (27)漸變
- (28)坐標系統
- (29)繪制設備
- (30)Graphics View Framework
- (31)貪吃蛇游戲(1)
- (32)貪吃蛇游戲(2)
- (33)貪吃蛇游戲(3)
- (34)貪吃蛇游戲(4)
- (35)文件
- (36)二進制文件讀寫
- (37)文本文件讀寫
- (38)存儲容器
- (39)遍歷容器
- (40)隱式數據共享
- (41)model/view 架構
- (42)QListWidget、QTreeWidget 和 QTableWidget
- (43)QStringListModel
- (44)QFileSystemModel
- (45)模型
- (46)視圖和委托
- (47)視圖選擇
- (48)QSortFilterProxyModel
- (49)自定義只讀模型
- (50)自定義可編輯模型
- (51)布爾表達式樹模型
- (52)使用拖放
- (53)自定義拖放數據
- (54)剪貼板
- (55)數據庫操作
- (56)使用模型操作數據庫
- (57)可視化顯示數據庫數據
- (58)編輯數據庫外鍵
- (59)使用流處理 XML
- (60)使用 DOM 處理 XML
- (61)使用 SAX 處理 XML
- (62)保存 XML
- (63)使用 QJson 處理 JSON
- (64)使用 QJsonDocument 處理 JSON
- (65)訪問網絡(1)
- (66)訪問網絡(2)
- (67)訪問網絡(3)
- (68)訪問網絡(4)
- (69)進程
- (70)進程間通信
- (71)線程簡介
- (72)線程和事件循環
- (73)Qt 線程相關類
- (74)線程和 QObject
- (75)線程總結
- (76)QML 和 QtQuick 2
- (77)QML 語法
- (78)QML 基本元素
- (79)QML 組件
- (80)定位器
- (81)元素布局
- (82)輸入元素
- (83)Qt Quick Controls
- (84)Repeater
- (85)動態視圖
- (86)視圖代理
- (87)模型-視圖高級技術
- (88)Canvas
- (89)Canvas(續)