Qt 的模型/视图结构(Model/View Architecture)是一种用于分离数据和其显示方式的设计模式,特别适合处理大量数据(如数据库表、文件系统、树形结构等)。它通过将数据的表示(模型)与数据的显示(视图)解耦,从而使得数据和 UI 表现彼此独立,允许更灵活和高效地管理和呈现数据。
模型/视图结构的核心组件
Qt 的模型/视图结构主要由以下三个部分组成:
- 模型(Model)
- 视图(View)
- 委托(Delegate)
1. 模型(Model)
模型负责存储和管理数据,并提供接口让视图和委托可以访问和修改数据。模型类的主要任务是将底层数据转换为视图所需的形式,并处理数据的变更。
Qt 提供了三种常用的模型基类:
QAbstractItemModel
: 所有模型的基础类。QStandardItemModel
: 提供了一个基于QStandardItem
的标准模型,适用于大部分场景。QAbstractListModel
: 适用于简单的线性数据(如列表)的模型。QAbstractTableModel
: 适用于二维表格数据的模型。QAbstractTreeModel
: 适用于树形结构数据的模型。
模型的职责:
- 提供数据的读取接口(如
data()
)。 - 提供数据的修改接口(如
setData()
)。 - 提供数据结构信息(如行数和列数:
rowCount()
和columnCount()
)。 - 支持信号
dataChanged()
,通知视图更新。
2. 视图(View)
视图负责显示模型中的数据。视图对象从模型中提取数据,并将其呈现在用户界面上。不同类型的视图可以使用相同的模型,展示数据的不同表现形式。
Qt 提供了以下几种标准视图类:
QListView
: 适用于显示列表数据的视图。QTableView
: 适用于显示二维表格数据的视图。QTreeView
: 适用于显示树形结构数据的视图。QColumnView
: 适用于分栏式浏览的视图。
视图的职责:
- 从模型中请求数据并在界面上呈现。
- 响应用户的交互,如选择、编辑、排序等。
- 将用户的操作(如编辑)反馈给模型。
3. 委托(Delegate)
委托负责渲染单元格内容,并处理编辑数据的输入。默认情况下,Qt 使用 QStyledItemDelegate
来绘制数据项和处理用户交互,但你可以自定义委托来控制项的外观和编辑行为。
委托的职责:
- 绘制数据项的外观(如字体、颜色、格式等)。
- 提供编辑控件,当用户需要修改数据时,委托可以提供编辑器。
- 处理用户输入的验证、提交等逻辑。
你可以通过自定义委托来控制每个数据项的呈现和编辑行为,通常继承 QItemDelegate
或 QStyledItemDelegate
实现自定义绘制和编辑逻辑。
模型/视图架构的工作流程
-
模型 是数据的持有者。它不会直接与用户交互,而是通过信号-槽机制与视图保持同步。视图可以从模型中读取数据,也可以向模型写入数据。
-
视图 显示来自模型的数据。视图会调用模型的
data()
方法来获得要显示的数据,并且会调用setData()
方法将用户的修改传递给模型。 -
委托 负责绘制视图中的每个数据项。如果用户需要编辑某个数据项,委托会创建一个输入控件来处理用户输入,之后将修改后的数据提交给模型。
核心功能示例
-
QTableView 和 QStandardItemModel
QTableView
是一个二维表格的视图,而QStandardItemModel
是一个方便使用的标准数据模型。
import sys from PyQt5.QtWidgets import QApplication, QTableView, QStandardItemModel, QStandardItem app = QApplication(sys.argv) # 创建一个 QStandardItemModel model = QStandardItemModel(4, 2) # 4 行 2 列 model.setHorizontalHeaderLabels(['Name', 'Age']) # 填充数据 model.setItem(0, 0, QStandardItem('Alice')) model.setItem(0, 1, QStandardItem('24')) model.setItem(1, 0, QStandardItem('Bob')) model.setItem(1, 1, QStandardItem('30')) # 创建一个 QTableView 并设置模型 view = QTableView() view.setModel(model) view.show() sys.exit(app.exec_())
-
自定义模型
可以通过继承QAbstractTableModel
创建自定义模型。如下例展示了如何创建一个只读的表格模型。from PyQt5.QtCore import Qt, QAbstractTableModel class MyTableModel(QAbstractTableModel): def __init__(self, data): super().__init__() self._data = data def rowCount(self, index): return len(self._data) def columnCount(self, index): return len(self._data[0]) def data(self, index, role): if role == Qt.DisplayRole: return self._data[index.row()][index.column()] data = [ [1, 2, 3], [4, 5, 6], [7, 8, 9], ] model = MyTableModel(data) view = QTableView() view.setModel(model) view.show()
模型/视图结构的优点
- 解耦数据和显示逻辑:模型不关心数据如何显示,视图不关心数据的来源。
- 高扩展性:可以使用不同的视图来显示相同的数据,例如,可以同时使用
QTableView
和QListView
来显示相同的模型。 - 易于维护:将数据和 UI 分离后,代码的维护和扩展变得更加方便。
- 大数据支持:使用懒加载的模型来处理大量数据时效率更高,因为数据只有在需要时才会加载。
总结
Qt 的模型/视图结构通过将数据管理(模型)与数据展示(视图)分离,提供了灵活、高效的数据处理方式。它特别适用于需要展示复杂数据结构的应用,如表格、树形结构或列表。在此基础上,委托可以进一步增强视图的表现力,使得模型/视图结构既灵活又强大。