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

发布于:2025-09-03 ⋅ 阅读:(13) ⋅ 点赞:(0)

本文将详细介绍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的构造函数中初始化数据模型并与视图关联:

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. 添加数据功能

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

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. 插入数据功能

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

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. 删除数据功能

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

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

代码解析:

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

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

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

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. 清空列表功能

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

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

代码解析:

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

8. 初始化数据功能

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

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

代码解析:

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

完整代码

mainwindow.h

#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

#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基本用法

// 创建文件系统模型
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. 多视图数据同步:同一个模型设置到多个视图,实现数据同步更新