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. 多视图数据同步:同一个模型设置到多个视图,实现数据同步更新
相关推荐
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner3 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz8 天前
QML Hello World 入门示例
qt
xcyxiner11 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner11 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner12 天前
DicomViewer (添加模型类)3
qt
xcyxiner12 天前
DicomViewer (目录调整) 2
qt
xcyxiner13 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00614 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术14 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript