PyQt学习系列02-模型-视图架构与数据管理
PyQt学习系列笔记(Python Qt框架)
第二课:PyQt的模型-视图架构与数据管理
一、模型-视图架构概述
1.1 什么是模型-视图架构?
模型-视图(Model-View)是Qt框架中用于数据展示和交互的核心设计模式。它将数据管理(模型)与用户界面(视图)分离,使得开发者可以灵活地处理复杂的数据操作,同时保持界面的简洁和高效。
核心组件:
- 模型(Model):负责存储和管理数据(如表格、列表、树形结构等)。
- 视图(View):负责将数据以可视化形式展示给用户(如
QTableView
、QListView
)。 - 委托(Delegate):负责控制数据的编辑和显示方式(如单元格的外观和交互)。
优势:
- 数据与界面解耦,便于维护和扩展。
- 支持多种数据源(内存数据、文件系统、数据库等)。
- 提供丰富的内置模型和视图组件,简化开发流程。
二、模型(Model)详解
2.1 模型的分类
PyQt提供了以下常用的模型类:
模型类 | 功能 |
---|---|
QStandardItemModel | 通用内存模型,支持表格、列表、树形结构 |
QFileSystemModel | 文件系统模型,用于浏览文件和目录 |
QSqlTableModel | 数据库模型,用于操作SQL数据库中的表 |
示例:创建一个QStandardItemModel
并填充数据
from PyQt5.QtCore import QStandardItemModel, QStandardItem# 创建模型
model = QStandardItemModel(3, 2) # 3行2列
model.setHorizontalHeaderLabels(["姓名", "年龄"])# 填充数据
model.setItem(0, 0, QStandardItem("张三"))
model.setItem(0, 1, QStandardItem("25"))
model.setItem(1, 0, QStandardItem("李四"))
model.setItem(1, 1, QStandardItem("30"))
2.2 模型的信号与槽
模型通过信号通知视图数据的变化,常见的信号包括:
dataChanged(index, index, role)
:数据项更新。rowsInserted(parent, start, end)
:插入新行。rowsRemoved(parent, start, end)
:删除行。
示例:监听数据变化
def on_data_changed(top_left, bottom_right, roles):print("数据已更新")model.dataChanged.connect(on_data_changed)
三、视图(View)详解
3.1 常用视图组件
视图类 | 功能 |
---|---|
QTableView | 表格视图,用于展示二维数据 |
QListView | 列表视图,用于展示一维数据 |
QTreeView | 树形视图,用于展示层次化数据 |
示例:使用QTableView
展示数据
from PyQt5.QtWidgets import QApplication, QTableViewapp = QApplication([])
view = QTableView()
view.setModel(model) # 绑定模型
view.show()
app.exec_()
3.2 视图的交互功能
视图支持多种用户交互操作:
- 选择模式:
QAbstractItemView.SingleSelection
、MultiSelection
。 - 编辑模式:
QAbstractItemView.EditKeyPressed
、DoubleClicked
。 - 排序功能:通过
setSortingEnabled(True)
启用排序。
示例:设置选择模式和排序
view.setSelectionMode(QAbstractItemView.MultiSelection)
view.setSortingEnabled(True)
四、委托(Delegate)详解
4.1 什么是委托?
委托(Delegate)是模型-视图架构中用于控制数据项的显示和编辑方式的组件。默认情况下,视图使用QStyledItemDelegate
处理数据项,但开发者可以通过继承QItemDelegate
或QStyledItemDelegate
自定义显示逻辑。
常见场景:
- 自定义单元格的样式(如颜色、字体)。
- 实现复杂的编辑控件(如下拉框、日期选择器)。
示例:自定义委托(修改单元格背景色)
from PyQt5.QtWidgets import QStyledItemDelegate, QColorclass ColorDelegate(QStyledItemDelegate):def initStyleOption(self, option, index):super().initStyleOption(option, index)option.backgroundBrush = QColor("lightblue") # 设置背景色view.setItemDelegate(ColorDelegate())
五、文件系统模型(QFileSystemModel)
5.1 功能概述
QFileSystemModel
是Qt提供的用于操作文件系统的模型,支持浏览目录、文件属性、大小等信息。
常用方法:
setRootPath(path)
:设置根目录。filePath(index)
:获取指定索引的文件路径。isDir(index)
:判断是否为目录。
示例:展示文件系统
from PyQt5.QtCore import QFileSystemModelfile_model = QFileSystemModel()
file_model.setRootPath(QDir.rootPath()) # 设置根目录为系统根目录
view.setModel(file_model)
view.setRootIndex(file_model.index("/")) # 显示根目录下的内容
六、数据库模型(QSqlTableModel)
6.1 功能概述
QSqlTableModel
是用于操作SQL数据库的模型,支持对数据库表的增删改查操作。
步骤:
- 连接数据库。
- 创建
QSqlTableModel
并绑定表。 - 将模型绑定到视图。
示例:操作SQLite数据库
from PyQt5.QtSql import QSqlDatabase, QSqlTableModel# 连接数据库
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("test.db")
db.open()# 创建表
query = QSqlQuery()
query.exec_("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")# 创建模型
model = QSqlTableModel(db=db)
model.setTable("users")
model.select() # 加载数据# 绑定视图
view.setModel(model)
view.show()
七、自定义模型(继承QAbstractItemModel)
7.1 实现自定义模型
对于复杂的数据结构,开发者可以通过继承QAbstractItemModel
实现自定义模型。需要重写以下方法:
index(row, column, parent)
:返回指定位置的索引。parent(index)
:返回父索引。rowCount(parent)
:返回行数。columnCount(parent)
:返回列数。data(index, role)
:返回数据项的内容。
示例:实现一个简单的树形模型
from PyQt5.QtCore import QAbstractItemModel, QModelIndex, Qtclass TreeModel(QAbstractItemModel):def __init__(self, data, parent=None):super().__init__(parent)self._data = data # 数据结构为嵌套字典def index(self, row, column, parent=QModelIndex()):if not parent.isValid():parent_item = self._dataelse:parent_item = parent.internalPointer()child_item = parent_item.get("children", [])[row]return self.createIndex(row, column, child_item)def parent(self, index):if not index.isValid():return QModelIndex()child_item = index.internalPointer()parent_item = child_item.get("parent")if parent_item is None:return QModelIndex()return self.createIndex(parent_item.row(), 0, parent_item)def rowCount(self, parent=QModelIndex()):if not parent.isValid():parent_item = self._dataelse:parent_item = parent.internalPointer()return len(parent_item.get("children", []))def columnCount(self, parent=QModelIndex()):return 1def data(self, index, role=Qt.DisplayRole):if role == Qt.DisplayRole:item = index.internalPointer()return item.get("name")return None# 使用自定义模型
data = {"name": "根节点","children": [{"name": "子节点1", "parent": {"row": 0, "column": 0}},{"name": "子节点2", "parent": {"row": 0, "column": 0}}]
}
model = TreeModel(data)
view = QTreeView()
view.setModel(model)
view.show()
八、模型-视图的高级功能
8.1 筛选和排序
通过QSortFilterProxyModel
可以实现数据的动态筛选和排序。
示例:实现模糊搜索
from PyQt5.QtCore import QSortFilterProxyModelproxy = QSortFilterProxyModel()
proxy.setSourceModel(model)
proxy.setFilterKeyColumn(0) # 按第一列筛选
proxy.setFilterRegExp("张") # 筛选包含"张"的行
view.setModel(proxy)
8.2 多线程加载数据
对于大数据量的模型,建议使用QThread
或QFuture
在后台线程加载数据,避免阻塞主线程。
示例:使用QThread
加载数据
from PyQt5.QtCore import QThread, pyqtSignalclass DataLoader(QThread):data_loaded = pyqtSignal(list)def run(self):# 模拟耗时操作data = ["数据1", "数据2", "数据3"]self.data_loaded.emit(data)loader = DataLoader()
loader.data_loaded.connect(lambda data: model.update_data(data))
loader.start()
九、常见问题与解决方案
9.1 模型与视图的数据不同步
原因:模型未正确通知视图数据变化。
解决方法:确保在修改数据后调用model.dataChanged.emit()
。
9.2 视图无法显示自定义模型
原因:未正确实现index()
或parent()
方法。
解决方法:检查索引生成逻辑,确保createIndex()
的参数正确。
十、总结与下一步
本节课重点讲解了PyQt的模型-视图架构,包括:
- 模型(Model):数据管理的核心,支持多种数据源。
- 视图(View):数据展示的组件,如
QTableView
。 - 委托(Delegate):控制数据的显示和编辑方式。
- 文件系统和数据库模型:快速集成文件和数据库操作。
- 自定义模型:通过继承
QAbstractItemModel
实现复杂数据结构。
下节课预告:
第三课将深入讲解PyQt的动画与过渡效果,包括QPropertyAnimation
、QSequentialAnimationGroup
的使用,以及如何为界面添加动态效果。请持续关注后续内容!
参考资料:
- PyQt官方文档 - Model/View Programming
- Qt官方教程 - Model/View Framework
- CSDN PyQt5教程