当前位置: 首页 > web >正文

PyQt学习系列02-模型-视图架构与数据管理

PyQt学习系列笔记(Python Qt框架)

第二课:PyQt的模型-视图架构与数据管理


一、模型-视图架构概述

1.1 什么是模型-视图架构?

模型-视图(Model-View)是Qt框架中用于数据展示和交互的核心设计模式。它将数据管理(模型)与用户界面(视图)分离,使得开发者可以灵活地处理复杂的数据操作,同时保持界面的简洁和高效。

核心组件

  • 模型(Model):负责存储和管理数据(如表格、列表、树形结构等)。
  • 视图(View):负责将数据以可视化形式展示给用户(如QTableViewQListView)。
  • 委托(Delegate):负责控制数据的编辑和显示方式(如单元格的外观和交互)。

优势

  1. 数据与界面解耦,便于维护和扩展。
  2. 支持多种数据源(内存数据、文件系统、数据库等)。
  3. 提供丰富的内置模型和视图组件,简化开发流程。

二、模型(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.SingleSelectionMultiSelection
  • 编辑模式QAbstractItemView.EditKeyPressedDoubleClicked
  • 排序功能:通过setSortingEnabled(True)启用排序。

示例:设置选择模式和排序

view.setSelectionMode(QAbstractItemView.MultiSelection)
view.setSortingEnabled(True)

四、委托(Delegate)详解

4.1 什么是委托?

委托(Delegate)是模型-视图架构中用于控制数据项的显示和编辑方式的组件。默认情况下,视图使用QStyledItemDelegate处理数据项,但开发者可以通过继承QItemDelegateQStyledItemDelegate自定义显示逻辑。

常见场景

  • 自定义单元格的样式(如颜色、字体)。
  • 实现复杂的编辑控件(如下拉框、日期选择器)。

示例:自定义委托(修改单元格背景色)

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数据库的模型,支持对数据库表的增删改查操作。

步骤

  1. 连接数据库。
  2. 创建QSqlTableModel并绑定表。
  3. 将模型绑定到视图。

示例:操作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 多线程加载数据

对于大数据量的模型,建议使用QThreadQFuture在后台线程加载数据,避免阻塞主线程。

示例:使用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的模型-视图架构,包括:

  1. 模型(Model):数据管理的核心,支持多种数据源。
  2. 视图(View):数据展示的组件,如QTableView
  3. 委托(Delegate):控制数据的显示和编辑方式。
  4. 文件系统和数据库模型:快速集成文件和数据库操作。
  5. 自定义模型:通过继承QAbstractItemModel实现复杂数据结构。

下节课预告
第三课将深入讲解PyQt的动画与过渡效果,包括QPropertyAnimationQSequentialAnimationGroup的使用,以及如何为界面添加动态效果。请持续关注后续内容!


参考资料

  1. PyQt官方文档 - Model/View Programming
  2. Qt官方教程 - Model/View Framework
  3. CSDN PyQt5教程
http://www.xdnf.cn/news/8172.html

相关文章:

  • 家政维修平台实战:08搭建服务分类
  • Excel合并单元格后,如何自动批量生成序号列
  • 三格电子——欧姆龙 CJ/CP系列 PLC 串口转网口详解
  • 计算机视觉与深度学习 | 用于图像分割的自监督学习(Self-Supervised Learning)方法综述
  • flutter dart class语法说明、示例
  • Chrome 插件网络请求的全面指南
  • python 打卡DAY27
  • Golang 并发小结
  • Java进阶之新特性
  • 大数据 笔记
  • VS Code + Maven 创建项目
  • Phantom 视频生成的流程
  • Python中accumulate方法
  • 【KWDB 2025 创作者计划】_从部署开始了解KWDB
  • 互联网大厂Java求职面试:企业知识库与AI大模型深度融合架构
  • HarmonyOS学习——UIAbility组件(下)
  • nvm版本管理下pnpm 安装失败问题解决
  • labview实现两路波形图数据采集
  • AI智能分析网关V4区域入侵检测算法:全功能覆盖,多场景守护安防安全
  • 零基础弄懂 ngx_http_slice_module分片缓存加速
  • HJ101 输入整型数组和排序标识【牛客网】
  • Spring Bean 的定义与管理、配置方式详解
  • 【Dify平台】使用Dify API 实现网页内嵌式AI助手
  • 前端图片裁剪上传全流程详解:从预览到上传的完整流程
  • Intel oneMKL 入门
  • 【1——Android端添加隐私协议(unity)1/3】
  • 谷歌开源医疗领域AI语言模型速递:medgemma-27b-text-it
  • 场景化应用实战系列四:基于 YOLO V5 的漫画人物检测
  • 【信息系统项目管理师】第16章:项目采购管理 - 23个经典题目及详解
  • 乘最多水的容器 | 算法 | 给定一个整数数组。有n条垂线。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。