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

news2025/5/29 14:42: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, QTableView

app = 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, QColor

class 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 QFileSystemModel

file_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, Qt

class 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._data
        else:
            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._data
        else:
            parent_item = parent.internalPointer()
        return len(parent_item.get("children", []))

    def columnCount(self, parent=QModelIndex()):
        return 1

    def 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 QSortFilterProxyModel

proxy = QSortFilterProxyModel()
proxy.setSourceModel(model)
proxy.setFilterKeyColumn(0)  # 按第一列筛选
proxy.setFilterRegExp("张")  # 筛选包含"张"的行
view.setModel(proxy)

8.2 多线程加载数据

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

示例:使用QThread加载数据

from PyQt5.QtCore import QThread, pyqtSignal

class 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.coloradmin.cn/o/2387426.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

KT6368A通过蓝牙芯片获取手机时间详细说明,对应串口指令举例

一、功能简介 KT6368A双模蓝牙芯片支持连接手机,获取手机的日期、时间信息,可以同步RTC时钟 1、无需安装任何app,直接使用系统蓝牙即可实现 2、同时它不影响音频蓝牙,还支持一些简单的AT指令进行操作 3、实现的方式&#xff1…

计算机网络实验课(二)——抓取网络数据包,并实现根据条件过滤抓取的以太网帧,分析帧结构

文章目录 一、添加控件二、代码分析2.1 代码2.2 控件初始化2.3 打开和关闭设备2.4 开始和结束捕获2.5 设置捕获条件2.6 捕获数据包 三、运行程序四、结果分析 提要:如果你通过vs打开.sln文件,然后代码界面或者前端界面都没找到,视图里面也没找…

78. Subsets和90. Subsets II

目录 78.子集 方法一、迭代法实现子集枚举 方法二、递归法实现子集枚举 方法三、根据子集元素个数分情况收集 方法四、直接回溯法 90.子集二 方法一、迭代法实现子集枚举 方法二、递归法实现子集枚举 方法三、根据子集元素个数分情况收集 方法四、直接回溯法 78.子集…

ElasticSearch整合SpringBoot

ElasticSearch 整合SpringBoot ES官方提供了各种不同语言的客户端。用来操作ES。这些客户端的本质就是组装DSL语句,通过HTTP请求发送给ES。 设计索引库 跟据数据库的表结构进行ES索引库的创建时。如果字段需要进行倒排索引的时候请为它指定分词器。如果该字段不是…

2025上半年软考高级系统架构设计师经验分享

笔者背景 笔者在成都工作近7年, 一直担任研发大头兵,平日工作主要涵盖应用开发(Java)与数仓开发,对主流数据库、框架等均有涉猎,但谈不上精通。 最近有一些职业上的想法,了解到软考有那么一丁点…

uni-app学习笔记十二-vue3中创建组件

通过组件,可以很方便地实现页面复用,减少重复页面的创建,减少重复代码。一个页面可以引入多个组件。下面介绍在HBuilder X中创建组件的方法: 一.组件的创建 1.选中项目,右键-->新建目录(文件夹),并将文…

一键启动多个 Chrome 实例并自动清理的 Bash 脚本分享!

目录 一、📦 脚本功能概览 二、📜 脚本代码一览 三、🔍 脚本功能说明 (一)✅ 支持批量启动多个 Chrome 实例 (二)✅ 每个实例使用独立用户数据目录 (三)✅ 启动后自…

4 月 62100 款 App 被谷歌下架!环比增长 28%

大家好,我是牢鹅!上周刚刚结束的 2025 年 Google I/O 开发者大会, Google Play 带来了一系列的更新,主要围绕提升优质 App 的"发现"、"互动"和"收入"三大核心内容。 这或许正是谷歌生态的一个侧影…

mediapipe标注视频姿态关键点(基础版加进阶版)

前言 手语视频流的识别有两种大的分类,一种是直接将视频输入进网络,一种是识别了关键点之后再进入网络。所以这篇文章我就要来讲讲如何用mediapipe对手语视频进行关键点标注。 代码 需要直接使用代码的,我就放这里了。环境自己配置一下吧&…

PCtoLCD2002如何制作6*8字符

如何不把“等比缩放”前的打勾取消,则无法修改为对应英文字符为6*8。 取消之后就可以更改了!

SmartPlayer与VLC播放RTMP:深度对比分析延迟、稳定性与功能

随着音视频直播技术的发展,RTMP(实时消息传输协议)成为了广泛应用于实时直播、在线教育、视频会议等领域的重要协议。为了确保优质的观看体验,RTMP播放器的选择至关重要。大牛直播SDK的SmartPlayer和VLC都是在行业中广受欢迎的播放…

Qt QPaintEvent绘图事件painter使用指南

绘制需在paintEvent函数中实现 用图片形象理解 如果加了刷子再用笔就相当于用笔画过的区域用刷子走 防雷达&#xff1a; 源文件 #include "widget.h" #include "ui_widget.h" #include <QDebug> #include <QPainter> Widget::Widget(QWidget…

伪创新-《软件方法》全流程引领AI-第1章 04

《软件方法》全流程引领AI-第1章 ABCD工作流-01 对PlantUML们的评价-《软件方法》全流程引领AI-第1章 02 AI辅助的建模步骤-《软件方法》全流程引领AI-第1章 03 第1章 ABCD工作流 1.5 警惕和揭秘伪创新 初中数学里要学习全等三角形、相似三角形、SSS、SAS……&#xff0c;到…

【iOS】 锁

iOS 锁 文章目录 iOS 锁前言线程安全锁互斥锁pthread_mutexsynchronized (互斥递归锁)synchronized问题:小结 NSLockNSRecursiveLockNSConditionNSConditionLock 自旋锁OSSpinLock(已弃用)atomicatomic修饰的属性绝对安全吗?os_unfair_lock 读写锁互斥锁和自旋锁的对比 小结使…

uni-app学习笔记十五-vue3页面生命周期(一)

页面生命周期概览 vue3页面生命周期如下图所示&#xff1a; onLoad 此时页面还未显示&#xff0c;没有开始进入的转场动画&#xff0c;页面dom还不存在。 所以这里不能直接操作dom&#xff08;可以修改data&#xff0c;因为vue框架会等待dom准备后再更新界面&#xff09;&am…

《软件工程》第 14 章 - 持续集成

在软件工程的开发流程中&#xff0c;持续集成是保障代码质量与开发效率的关键环节。本章将围绕持续集成的各个方面展开详细讲解&#xff0c;结合 Java 代码示例与可视化图表&#xff0c;帮助读者深入理解并实践相关知识。 14.1 持续集成概述 14.1.1 持续集成的相关概念 持续集…

Orpheus-TTS:AI文本转语音,免费好用的TTS系统

名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、Orpheus-TTS&#xff1a;重新定义语音合成的标准1. 什么是Orpheus-TTS&#xff…

STM32 Keil工程搭建 (手动搭建)流程 2025年5月27日07:42:09

STM32 Keil工程搭建 (手动搭建)流程 觉得麻烦跳转到最底部看总配置图 1.获取官方标准外设函数库 内部结构如下: 文件夹功能分别为 图标(用不上)库函数(重点) Libraries/ ├── CMSIS/ # ARM Cortex-M Microcontroller Software Interface Standard…

OpenGL Chan视频学习-7 Writing a Shader inOpenGL

bilibili视频链接&#xff1a; 【最好的OpenGL教程之一】https://www.bilibili.com/video/BV1MJ411u7Bc?p5&vd_source44b77bde056381262ee55e448b9b1973 函数网站&#xff1a; docs.gl 说明&#xff1a; 1.之后就不再整理具体函数了&#xff0c;网站直接翻译会更直观也会…

顶会新方向:卡尔曼滤波+目标检测

卡尔曼虑波&#xff0b;目标检测创新结合&#xff0c;新作准确率突破100%! 一个有前景且好发论文的方向:卡尔曼滤波&#xff0b;目标检测! 这种创新结合&#xff0c;得到学术界的广泛认可&#xff0c;多篇成果陆续登上顶会顶刊。例如无人机竞速系统 Swift&#xff0c;登上nat…