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

QT--模型/视图

在 Qt 中,模型/视图架构(Model/View Architecture) 是一种用于分离数据和用户界面的设计模式。它将数据的存储(模型)与数据的显示(视图)分开,从而提高了代码的可维护性和灵活性。模型/视图架构广泛应用于 Qt 的 GUI 开发中,尤其是在处理表格、列表、树等复杂数据结构时。


1. 模型/视图架构的核心概念

1.1 模型(Model)

  • 模型负责管理数据,并提供接口供视图和委托(Delegate)访问数据。
  • 模型通过信号和槽机制通知视图数据的变化。
  • Qt 提供了多种内置模型,如 QStandardItemModelQStringListModelQSqlTableModel 等。

1.2 视图(View)

  • 视图负责显示模型中的数据,并提供用户交互功能(如选择、排序等)。
  • 视图从模型中获取数据,并将其显示在用户界面上。
  • Qt 提供了多种内置视图,如 QListViewQTableViewQTreeView 等。

1.3 委托(Delegate)

  • 委托负责数据的编辑和显示样式。
  • 委托可以自定义单元格的显示方式和编辑行为。
  • Qt 提供了默认的委托 QStyledItemDelegate,也可以自定义委托。

2. 模型/视图架构的类层次结构

2.1 模型类

  • QAbstractItemModel:所有模型的基类。
  • QStandardItemModel:通用的模型,适合存储任意结构的数据。
  • QStringListModel:用于存储字符串列表的简单模型。
  • QFileSystemModel:用于显示文件系统的模型。
  • QSqlTableModel:用于与数据库交互的模型。

2.2 视图类

  • QAbstractItemView:所有视图的基类。
  • QListView:用于显示列表数据的视图。
  • QTableView:用于显示表格数据的视图。
  • QTreeView:用于显示树形数据的视图。

2.3 委托类

  • QAbstractItemDelegate:所有委托的基类。
  • QStyledItemDelegate:默认的委托,支持样式化和编辑。
  • QItemDelegate:功能与 QStyledItemDelegate 类似,但更轻量级。

3. 模型/视图的基本使用

以下是一个简单的示例,展示如何使用 QStringListModel 和 QListView 来显示字符串列表。

3.1 使用 QStringListModel 和 QListView

#include <QApplication>
#include <QListView>
#include <QStringListModel>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 创建模型
    QStringListModel model;
    QStringList list;
    list << "Apple" << "Banana" << "Cherry" << "Date";
    model.setStringList(list);  // 设置数据到模型

    // 创建视图
    QListView view;
    view.setModel(&model);  // 将模型绑定到视图
    view.setWindowTitle("QListView Example");
    view.resize(200, 300);
    view.show();

    return app.exec();
}

3.2 运行效果

  • 视图会显示一个列表,内容为 AppleBananaCherry 和 Date
  • 如果修改模型中的数据,视图会自动更新。

4. 自定义模型

如果内置模型无法满足需求,可以继承 QAbstractItemModel 或其子类来实现自定义模型。

4.1 自定义模型的示例

以下是一个简单的自定义模型,用于存储和显示一个二维表格数据。

#include <QAbstractTableModel>
#include <QDebug>

class MyTableModel : public QAbstractTableModel {
    Q_OBJECT

public:
    MyTableModel(QObject *parent = nullptr) : QAbstractTableModel(parent) {
        // 初始化数据
        for (int row = 0; row < 3; ++row) {
            QVector<QString> rowData;
            for (int col = 0; col < 3; ++col) {
                rowData.append(QString("(%1,%2)").arg(row).arg(col));
            }
            m_data.append(rowData);
        }
    }

    // 返回行数
    int rowCount(const QModelIndex &parent = QModelIndex()) const override {
        return m_data.size();
    }

    // 返回列数
    int columnCount(const QModelIndex &parent = QModelIndex()) const override {
        return m_data.isEmpty() ? 0 : m_data.first().size();
    }

    // 返回数据
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
        if (!index.isValid())
            return QVariant();

        if (role == Qt::DisplayRole) {
            return m_data.at(index.row()).at(index.column());
        }

        return QVariant();
    }

private:
    QList<QVector<QString>> m_data;  // 存储数据的二维列表
};

4.2 使用自定义模型

#include <QApplication>
#include <QTableView>
#include "MyTableModel.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 创建自定义模型
    MyTableModel model;

    // 创建视图
    QTableView view;
    view.setModel(&model);  // 将模型绑定到视图
    view.setWindowTitle("Custom Table Model Example");
    view.resize(300, 200);
    view.show();

    return app.exec();
}

4.3 运行效果

  • 视图会显示一个 3x3 的表格,内容为 (0,0)(0,1)(0,2) 等。

5. 自定义委托

如果需要自定义单元格的显示或编辑行为,可以继承 QStyledItemDelegate 实现自定义委托。

5.1 自定义委托的示例

以下是一个简单的自定义委托,用于在单元格中显示红色背景的文本。

#include <QStyledItemDelegate>
#include <QPainter>

class MyDelegate : public QStyledItemDelegate {
    Q_OBJECT

public:
    MyDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}

    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
        if (index.column() == 1) {  // 仅对第二列应用自定义样式
            painter->fillRect(option.rect, Qt::red);  // 设置红色背景
            painter->drawText(option.rect, Qt::AlignCenter, index.data().toString());  // 绘制文本
        } else {
            QStyledItemDelegate::paint(painter, option, index);  // 使用默认样式
        }
    }
};

5.2 使用自定义委托

#include <QApplication>
#include <QTableView>
#include "MyTableModel.h"
#include "MyDelegate.h"

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 创建自定义模型
    MyTableModel model;

    // 创建视图
    QTableView view;
    view.setModel(&model);
    view.setItemDelegate(new MyDelegate(&view));  // 设置自定义委托
    view.setWindowTitle("Custom Delegate Example");
    view.resize(300, 200);
    view.show();

    return app.exec();
}

5.3 运行效果

  • 视图会显示一个 3x3 的表格,其中第二列的单元格背景为红色,文本居中显示。

6. 模型/视图架构的优势

6.1 分离数据与显示

  • 模型负责管理数据,视图负责显示数据,两者解耦,便于维护和扩展。
  • 例如,可以通过不同的视图(如 QTableView 或 QTreeView)显示相同的数据模型。

6.2 数据驱动的界面

  • 模型通过信号和槽机制通知视图数据的变化,视图会自动更新。
  • 例如,修改模型中的数据后,视图会立即反映变化。

6.3 灵活性和可扩展性

  • 可以轻松实现自定义模型、视图和委托,满足复杂的业务需求。
  • 例如,可以自定义模型来处理数据库数据,或自定义委托来实现复杂的单元格显示。

7. 模型/视图架构的常见应用场景

7.1 表格数据展示

  • 使用 QTableView 和 QStandardItemModel 展示二维表格数据。
  • 例如,展示 Excel 表格或数据库查询结果。

7.2 列表数据展示

  • 使用 QListView 和 QStringListModel 展示一维列表数据。
  • 例如,展示文件列表或配置项。

7.3 树形数据展示

  • 使用 QTreeView 和 QStandardItemModel 展示树形结构数据。
  • 例如,展示文件系统或组织结构。

7.4 数据库交互

  • 使用 QSqlTableModel 或 QSqlQueryModel 与数据库交互。
  • 例如,展示数据库表数据或执行查询操作。

8. 模型/视图架构的信号与槽

模型/视图架构通过信号和槽机制实现数据变化的通知和响应。以下是一些常用的信号和槽:

8.1 模型信号

  • dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight):当模型数据发生变化时发出。
  • rowsInserted(const QModelIndex &parent, int first, int last):当插入新行时发出。
  • rowsRemoved(const QModelIndex &parent, int first, int last):当删除行时发出。

8.2 视图信号

  • clicked(const QModelIndex &index):当用户点击视图中的项时发出。
  • doubleClicked(const QModelIndex &index):当用户双击视图中的项时发出。
  • activated(const QModelIndex &index):当用户激活视图中的项时发出(例如按下回车键)。

8.3 示例:响应视图的点击事件

#include <QApplication>
#include <QListView>
#include <QStringListModel>
#include <QDebug>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 创建模型
    QStringListModel model;
    QStringList list;
    list << "Apple" << "Banana" << "Cherry" << "Date";
    model.setStringList(list);

    // 创建视图
    QListView view;
    view.setModel(&model);
    view.setWindowTitle("Signal/Slot Example");
    view.resize(200, 300);

    // 连接视图的 clicked 信号
    QObject::connect(&view, &QListView::clicked, [](const QModelIndex &index) {
        qDebug() << "Clicked item:" << index.data().toString();
    });

    view.show();
    return app.exec();
}

9. 模型/视图架构的性能优化

9.1 只更新必要的数据

  • 当数据发生变化时,尽量只更新受影响的区域,而不是整个模型。
  • 例如,使用 dataChanged 信号时,指定受影响的范围。

9.2 使用分层模型

  • 对于大型数据集,可以使用分层模型(如 QTreeView)来减少内存占用和提高性能。

9.3 延迟加载数据

  • 对于需要从数据库或网络加载的数据,可以使用延迟加载策略,只在需要时加载数据。

9.4 优化委托

  • 自定义委托时,尽量减少不必要的绘制操作,以提高性能。

10. 总结

Qt 的模型/视图架构是一种强大的设计模式,用于分离数据和用户界面,提高代码的可维护性和灵活性。以下是一些关键点:

  • 模型:负责管理数据,提供接口供视图和委托访问数据。
  • 视图:负责显示数据,并提供用户交互功能。
  • 委托:负责数据的编辑和显示样式。
  • 信号与槽:用于模型和视图之间的通信。
  • 自定义模型和委托:可以实现复杂的业务需求。

通过合理使用模型/视图架构,可以构建高效、灵活且易于维护的应用程序。

 

 

 


http://www.kler.cn/a/454245.html

相关文章:

  • Vscode + gdbserver远程调试开发板指南:
  • 云计算时代携程的网络架构变迁
  • Python PyMupdf 去除PDF文档中Watermark标识水印
  • centos制作离线安装包
  • AES 与 SM4 加密算法:深度解析与对比
  • 前端网页开发学习(HTML+CSS+JS)有这一篇就够!
  • 如何使用 Django 框架创建简单的 Web 应用?
  • Android native+html5的混合开发
  • 我的 2024 年终总结
  • 设计模式の命令访问者迭代器模式
  • MIT实验笔记冲刺2 实验部分
  • 工作生活做事慢效率低原因及解决方案
  • C语言变量指针、指针变量、数组指针、指针数组
  • 流程图(二)利用python绘制网络图
  • shardingsphere分库分表项目实践5-自己用java写一个sql解析器+完整项目源码
  • 探秘“香水的 ChatGPT”:AI 开启嗅觉奇幻之旅!
  • 【自留】Unity VR入门
  • [原创](Modern C++)现代C++的第三方库的导入方式: 例如Visual Studio 2022导入GSL 4.1.0
  • python之打印、变量、格式化输出
  • SkyWalking服务监控、追踪、诊断可视化工具
  • Flink的Watermark水位线详解
  • 嵌入式学习-QT-Day09
  • Linux 简单命令总结
  • Android笔记(四十):ViewPager2嵌套RecyclerView滑动冲突进一步解决
  • 企业如何搭建安全的跨网文件安全交换管理系统
  • 人工智能的视觉天赋:一文读懂卷积神经网络