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

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教程

相关文章:

  • DOM API-JS通过文档对象树操作Doc和CSS
  • 其他有关Oracle BUFFER CACHE的优化思路
  • Go语言之Map 的基本操作-《Go语言实战指南》
  • LeetCode 257. 二叉树所有路径求解:回溯算法的深度解析与实践
  • MySQL中InnoDB引擎逻辑存储结构、B+树索引结构、B+树高度及存储数据量
  • 前端父元素flex布局设置左右padding时,input溢出父元素右内边距无效
  • 我的世界模组开发——物理学(1)
  • VPLC (VPLCnext) K8S
  • YOLO学习笔记 | YOLO11对象检测,实例分割,姿态评估的TensorRT部署c++
  • 企业网站架构部署与优化第4章Nginx核心功能
  • C++ HTTP框架推荐
  • AI|Java开发 IntelliJ IDEA中接入本地部署的deepseek方法
  • docker-安装部署于macOS11
  • 防震基座在半导体晶圆制造设备抛光机详细应用案例-江苏泊苏系统集成有限公司
  • 【HALCON 】深入理解 gray_histo_abs 灰度直方图算子
  • 动态网页爬取:Python如何获取JS加载的数据?
  • docker多阶段构建镜像
  • C++中的菱形继承问题
  • Go语言gopacket库的HTTP协议分析工具实现
  • Springboot3
  • 个人网站与企业网站区别/免费推广平台
  • wordpress slider 插件/家庭优化大师免费下载
  • 公司有必要建设网站吗/株洲百度seo
  • 宣武门网站建设/百度网址大全免费下载
  • app和网站的关系/广州疫情今天最新消息
  • 渐变配色网站/最全bt搜索引擎入口