从打包到解耦: Qt数据展示的正确姿势

前言

用PyQt写工具,初期用QListWidget很方便。但随着数据属性增多,界面和数据逻辑混在一起,维护变得困难。是时候重新审视并实践Qt的Model/View/Controller(MVC)架构了。本文旨在梳理这一模式,搞清楚其核心思想。

MVC:数据与界面的解耦

MVC的核心是分工,将应用程序拆分为三个独立但协作的部分。

1. Model(模型):数据的容器和管理者

  • 是什么:模型是数据的抽象。它不关心数据如何显示,只负责存储、管理数据,并提供统一的接口进行增删改查。
  • 核心职责
    • 持有数据。
    • 实现数据操作逻辑(如排序、过滤)。
    • 当数据变化时,发出信号(dataChanged)通知外界。
  • 在Qt中:通常继承自QAbstractItemModel或其子类。模型对视图一无所知,这是解耦的关键。

2. View(视图):数据的展示器

  • 是什么:视图是模型数据的可视化呈现。
  • 核心职责
    • 向模型请求数据(通过data()方法)。
    • 将获取的数据以特定形式(列表、表格、树)绘制在界面上。
    • 监听模型的信号,在数据变化时自动刷新显示。
  • 在Qt中QListView, QTableView, QTreeView等。视图本身不存储任何数据。

3. Controller/Delegate(控制器/代理):连接桥梁

在Qt的Model/View架构中,传统的“Controller”角色被分散了。

  • 用户交互(Controller):主要通过信号与槽机制实现。例如,点击视图中的一个按钮,视图发出信号,应用程序的某个槽函数接收信号并调用模型的方法去修改数据。这个连接过程就是控制逻辑。
  • 渲染与编辑(Delegate):这是Qt M/V的精髓。代理(Delegate)负责两件事:
    • 如何渲染:默认情况下,视图只是把模型返回的文本画出来。如果你想画一个进度条、一个下拉框或者一张图片,就需要自定义代理。
    • 如何编辑:当用户双击一个项时,代理会创建一个编辑器(如QLineEdit)让用户修改数据,修改完成后再将数据写回模型。

这种分离使得你可以用一个模型,搭配多个不同的视图和代理,实现多样化的展示和交互,而无需改动数据本身。

QListWidget 与 QListView:从便利到灵活

这两者都用来显示列表,但定位不同。

QListWidget:一体化便利组件

  • 特点:它是一个高级封装,内部自带一个简易模型。你直接操作的是QListWidgetItem,而不是数据本身。
  • 优点:简单、直接、快速上手。
  • 缺点:数据和视图强耦合。数据存储在QListWidgetItem对象中,不方便进行复杂的数据操作(如排序、过滤、数据库同步),性能在大量数据下也较差。

QListView:纯粹的视图

  • 特点:它只是一个“框”,本身不存储任何数据。必须给它设置一个模型(Model)才能工作。
  • 优点
    • 彻底解耦:数据逻辑在模型中,显示逻辑在视图中。
    • 高性能:模型可以根据视图的需要按需加载数据,轻松应对百万级数据量。
    • 灵活性:可搭配任何QAbstractItemModel子类,实现复杂的数据结构和展示。

何时选择

场景推荐使用原因
简单的设置项、日志显示QListWidget快速开发,代码量少
大量数据、动态更新QListView + Model高性能、易维护
数据源是数据库、文件系统QListView + Model模型负责与数据源交互,逻辑清晰
需要自定义显示样式(如图文混排)QListView + Delegate强大的自定义能力

常用数据模型:开箱即用的工具箱

Qt提供了一些预置的模型,可以直接使用。

1. QStandardItemModel

  • 定位:通用型模型。
  • 结构:基于项(QStandardItem),每个项都可以独立设置文本、图标、复选框等。可以轻松构建列表、表格和树状结构。
  • 适用:需要灵活控制每个单元格内容,但数据结构不复杂的场景。

2. QStringListModel

  • 定位:字符串列表专用。
  • 结构:直接包装一个QStringList
  • 适用:最简单的场景,只显示一个字符串列表。

3. QSqlQueryModel

  • 定位:数据库查询结果模型。
  • 结构:执行一个SQL查询,并将结果集作为模型数据。通常是只读的。
  • 适用:直接在QTableView中展示数据库查询结果。

4. 终极方案:自定义模型

当预置模型无法满足需求时(例如,你的数据源是一个复杂的C++对象列表,或者需要极致的性能优化),就需要自定义模型。

  • 方法:继承QAbstractListModel(用于列表)或QAbstractTableModel(用于表格)。
  • 核心:至少需要重写以下几个关键的纯虚函数:
    • rowCount():返回数据行数。
    • columnCount():返回数据列数(列表模型通常为1)。
    • data(index, role):视图通过此函数获取数据。index指定位置,role指定需要的数据类型(如Qt.DisplayRole表示文本,Qt.DecorationRole表示图标)。
    • flags(index):返回项的标志,如是否可选、可编辑等。

自定义模型虽然前期工作量稍大,但提供了对数据操作的最终控制权。

总结

  • QListWidget是便利工具,适用于简单场景。
  • 当数据和展示需要分离时,转向Model/View架构是必然选择。
  • Model管数据,View管展示,Delegate管渲染和编辑,信号/槽管交互。各司其职,代码清晰,易于扩展。
  • 根据数据源和复杂度,选择合适的预置模型或直接自定义模型,是高效开发的关键。

已发布

分类

来自

标签:

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注