Qt模型/视图编程详解:QStringListModel与多视图数据同步

本文将详细介绍Qt中的模型/视图编程框架,重点讲解QStringListModel的使用方法,以及如何实现多个视图之间的数据同步。

效果展示

项目概述

本应用主要实现以下功能:

  • 使用QListView和QTableView展示相同的数据
  • 使用QPlainTextEdit显示数据内容
  • 支持数据的添加、插入、删除和初始化操作
  • 实现多个视图之间的数据同步

模型/视图编程原理

1. 模型/视图架构概述

Qt的模型/视图架构将数据的存储(模型)和数据的显示(视图)分离开来,这种分离使得多个视图可以显示同一个模型的数据,并且可以独立地处理用户输入。

核心组件:

  • 模型(Model):负责管理数据,提供统一的接口供视图访问
  • 视图(View):负责显示模型中的数据,并处理用户交互
  • 委托(Delegate):负责渲染视图中的项目,并处理项目编辑

2. QStringListModel介绍

QStringListModel是Qt中一个简单的模型类,专门用于处理字符串列表数据。它继承自QAbstractListModel,提供了对字符串列表的基本操作接口。

主要特点:

  • 专门为字符串列表设计
  • 支持基本的增删改查操作
  • 可以同时用于列表视图和表格视图

实现步骤

1. 界面设计

首先在Qt Designer中创建主窗口,添加以下控件:

  • 三个GroupBox,分别包含ListView、TableView和PlainTextEdit
  • 五个PushButton:添加、插入、删除、加载到文本编辑框、清空列表、初始化
  • 工具栏和对应的Action:导入、保存、添加、插入、删除、预览、居左、居中、居右、粗体

2. 模型初始化和视图关联

在MainWindow的构造函数中初始化数据模型并与视图关联:

cpp 复制代码
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 创建QStringListModel对象,用于管理字符串列表数据
    // QStringListModel是Qt提供的专门用于处理字符串列表的模型类
    model = new QStringListModel(this);

    // 准备初始数据,包含几个中国主要城市
    QStringList addList = {"北京", "上海", "广州", "深圳", "杭州", "长沙"};

    // 将数据设置到模型中
    // setStringList()方法会将整个字符串列表设置为模型的数据
    model->setStringList(addList);

    // 将同一个模型设置到ListView和TableView
    // 这样两个视图将显示相同的数据,并且保持同步
    ui->listView->setModel(model);
    ui->tableView->setModel(model);
}

代码解析:

  • QStringListModel是专门为字符串列表设计的模型类,提供了对字符串列表的基本操作接口
  • setStringList()方法将字符串列表设置为模型的数据源
  • 同一个模型可以设置到多个视图,实现数据的同步显示

3. 添加数据功能

实现在列表尾部添加新数据的功能:

cpp 复制代码
void MainWindow::on_pushButtonAdd_clicked()
{
    // 在模型尾部插入一行空数据
    // insertRow()方法在指定位置插入新行,参数为行索引
    model->insertRow(model->rowCount());

    // 获取新插入行的索引
    // index()方法根据行号和列号创建模型索引
    QModelIndex index = model->index(model->rowCount() - 1, 0);
    
    // 设置新行的数据为"新的城市"
    // setData()方法设置指定索引的数据
    model->setData(index, "新的城市");

    // 在ListView中自动选中新添加的行
    // setCurrentIndex()方法设置当前选中的项
    ui->listView->setCurrentIndex(index);
}

代码解析:

  • insertRow()方法在指定位置插入新行,参数为行索引
  • index()方法根据行号和列号创建模型索引,用于定位模型中的特定项
  • setData()方法设置指定索引的数据
  • setCurrentIndex()方法设置视图中的当前选中项

4. 插入数据功能

实现在当前选中位置插入新数据的功能:

cpp 复制代码
void MainWindow::on_pushButtonInsert_clicked()
{
    // 获取ListView中当前选中的项的索引
    // currentIndex()方法返回当前选中的模型索引
    QModelIndex index = ui->listView->currentIndex();
    
    // 在当前选中行之前插入新行
    model->insertRow(index.row());
    
    // 设置新插入行的数据
    model->setData(index, "新的城市");
    
    // 保持选中新插入的行
    ui->listView->setCurrentIndex(index);
}

代码解析:

  • currentIndex()方法获取当前选中的模型索引
  • insertRow()方法在指定位置插入新行
  • 插入新行后,保持选中状态以便用户继续操作

5. 删除数据功能

实现删除当前选中数据的功能:

cpp 复制代码
void MainWindow::on_pushButtonDel_clicked()
{
    // 获取ListView中当前选中的项的索引
    QModelIndex index = ui->listView->currentIndex();
    
    // 删除当前选中的行
    // removeRow()方法删除指定行,参数为行索引
    model->removeRow(index.row());
}

代码解析:

  • removeRow()方法删除指定行,参数为行索引
  • 删除操作会同时更新所有使用该模型的视图

6. 加载数据到文本编辑框

实现将模型中的数据加载到文本编辑框的功能:

cpp 复制代码
void MainWindow::on_pushButtonLoadData2TextEdit_clicked()
{
    // 从模型中获取完整的字符串列表
    // stringList()方法返回模型中的所有字符串
    QStringList list = model->stringList();
    
    // 清空文本编辑框
    ui->plainTextEdit->clear();
    
    // 遍历字符串列表,将每个字符串添加到文本编辑框
    for(int i = 0; i < list.count(); i++) {
        // append()方法在文本编辑框末尾添加文本
        ui->plainTextEdit->append(list[i]);
    }
}

代码解析:

  • stringList()方法返回模型中的所有字符串
  • clear()方法清空文本编辑框的内容
  • append()方法在文本编辑框末尾添加文本

7. 清空列表功能

实现清空模型中所有数据的功能:

cpp 复制代码
void MainWindow::on_pushButtonClearList_clicked()
{
    // 删除模型中所有行
    // removeRows()方法删除从指定位置开始的指定数量的行
    // 参数1:起始行索引,参数2:要删除的行数
    model->removeRows(0, model->rowCount());
}

代码解析:

  • removeRows()方法删除从指定位置开始的指定数量的行
  • 参数1是起始行索引,参数2是要删除的行数
  • rowCount()方法返回模型中的总行数

8. 初始化数据功能

实现将模型数据重置为初始状态的功能:

cpp 复制代码
void MainWindow::on_pushButtonInit_clicked()
{
    // 准备初始数据
    QStringList addList = {"北京", "上海", "广州", "深圳", "杭州"};
    
    // 将初始数据设置到模型中
    model->setStringList(addList);
}

代码解析:

  • setStringList()方法将整个字符串列表设置为模型的数据
  • 这会替换模型中现有的所有数据

完整代码

mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTextEdit> // 文本编辑框头文件
#include <QStringListModel> // 字符串列表模型头文件

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    // 构造函数
    MainWindow(QWidget *parent = nullptr);
    
    // 析构函数
    ~MainWindow();

private slots:
    // 添加按钮点击槽函数
    void on_pushButtonAdd_clicked();

    // 插入按钮点击槽函数
    void on_pushButtonInsert_clicked();

    // 删除按钮点击槽函数
    void on_pushButtonDel_clicked();

    // 加载数据到文本编辑框按钮点击槽函数
    void on_pushButtonLoadData2TextEdit_clicked();

    // 清空列表按钮点击槽函数
    void on_pushButtonClearList_clicked();

    // 初始化按钮点击槽函数
    void on_pushButtonInit_clicked();

private:
    Ui::MainWindow *ui; // UI指针
    
    QStringListModel *model; // 字符串列表模型指针
};
#endif // MAINWINDOW_H

mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 创建QStringListModel对象,用于管理字符串列表数据
    model = new QStringListModel(this);

    // 准备初始数据,包含几个中国主要城市
    QStringList addList = {"北京", "上海", "广州", "深圳", "杭州", "长沙"};

    // 将数据设置到模型中
    model->setStringList(addList);

    // 将同一个模型设置到ListView和TableView
    // 这样两个视图将显示相同的数据,并且保持同步
    ui->listView->setModel(model);
    ui->tableView->setModel(model);
}

MainWindow::~MainWindow()
{
    delete ui; // 释放UI资源
}

// 添加按钮点击槽函数实现
void MainWindow::on_pushButtonAdd_clicked()
{
    // 在模型尾部插入一行空数据
    model->insertRow(model->rowCount());

    // 获取新插入行的索引
    QModelIndex index = model->index(model->rowCount() - 1, 0);
    
    // 设置新行的数据为"新的城市"
    model->setData(index, "新的城市");

    // 在ListView中自动选中新添加的行
    ui->listView->setCurrentIndex(index);
}

// 插入按钮点击槽函数实现
void MainWindow::on_pushButtonInsert_clicked()
{
    // 获取ListView中当前选中的项的索引
    QModelIndex index = ui->listView->currentIndex();
    
    // 在当前选中行之前插入新行
    model->insertRow(index.row());
    
    // 设置新插入行的数据
    model->setData(index, "新的城市");
    
    // 保持选中新插入的行
    ui->listView->setCurrentIndex(index);
}

// 删除按钮点击槽函数实现
void MainWindow::on_pushButtonDel_clicked()
{
    // 获取ListView中当前选中的项的索引
    QModelIndex index = ui->listView->currentIndex();
    
    // 删除当前选中的行
    model->removeRow(index.row());
}

// 加载数据到文本编辑框按钮点击槽函数实现
void MainWindow::on_pushButtonLoadData2TextEdit_clicked()
{
    // 从模型中获取完整的字符串列表
    QStringList list = model->stringList();
    
    // 清空文本编辑框
    ui->plainTextEdit->clear();
    
    // 遍历字符串列表,将每个字符串添加到文本编辑框
    for(int i = 0; i < list.count(); i++) {
        ui->plainTextEdit->append(list[i]);
    }
}

// 清空列表按钮点击槽函数实现
void MainWindow::on_pushButtonClearList_clicked()
{
    // 删除模型中所有行
    model->removeRows(0, model->rowCount());
}

// 初始化按钮点击槽函数实现
void MainWindow::on_pushButtonInit_clicked()
{
    // 准备初始数据
    QStringList addList = {"北京", "上海", "广州", "深圳", "杭州"};
    
    // 将初始数据设置到模型中
    model->setStringList(addList);
}

文件系统模型使用详解

除了QStringListModel,Qt还提供了QFileSystemModel用于文件系统操作。虽然本示例中没有使用,但了解它的基本用法对模型/视图编程很有帮助。

QFileSystemModel基本用法

cpp 复制代码
// 创建文件系统模型
QFileSystemModel *fileModel = new QFileSystemModel(this);

// 设置根路径
fileModel->setRootPath(QDir::currentPath());

// 将模型设置到视图
ui->treeView->setModel(fileModel);
ui->treeView->setRootIndex(fileModel->index(QDir::currentPath()));

主要特点:

  • 专门用于表示本地文件系统
  • 自动监视文件系统的变化并更新模型
  • 提供文件图标、大小、修改日期等信息

字符串链表模型使用详解

QStringListModel是QAbstractListModel的子类,专门用于处理字符串列表。它提供了对字符串列表的基本操作接口,可以同时用于列表视图和表格视图。

QStringListModel常用方法

  1. setStringList() - 设置模型的字符串列表
  2. stringList() - 获取模型的字符串列表
  3. insertRow() - 在指定位置插入新行
  4. removeRow() - 删除指定行
  5. setData() - 设置指定索引的数据
  6. data() - 获取指定索引的数据

总结

本文详细介绍了Qt中的模型/视图编程框架,重点讲解了QStringListModel的使用方法。通过这个示例,我们学习了:

  1. 模型/视图架构原理:数据与显示的分离,实现多个视图同步
  2. QStringListModel的基本使用方法:创建模型、设置数据、与视图关联
  3. 数据操作功能实现:添加、插入、删除、清空和初始化数据
  4. 多视图数据同步:同一个模型设置到多个视图,实现数据同步更新
相关推荐
Scott9999HH1 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社2 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海2 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖3 小时前
JDK 26 新特性详解
java·开发语言
马优晨4 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区5 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大6 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai6 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜6 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa7 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio