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

QT基础十二、标准项模型:QStandardItemModel

目录

一、简介

二、核心功能

三、准备材料

1、所需要的action

 2、将action添加进菜单栏里

 3、最终样式​编辑

 4、准备数据文件

四、项目代码

1、需要用到的头文件与变量

2、初始化组件

3、打开txt文件,并导入其中数据

4、初始化standModel的数据

 5、在尾部添加一行数据

6、插入一行数据

7、删除一行数据

8、预览模式,可以查看将要保存的状态

9、保存文件

 10、将表格内的内容居中

11、 将表格内的内容居左

12、 将表格内的内容居右

13、设置字体

 14、当选择的标签变化时,更新字体种类

 15、运行结果

五、常用接口

QStandardItemModel

1、设置行列数 :

2、插入项:

3、获取项:

4、清除模型:

QStandardItem

1、设置文本:

2、设置图标:

3、设置子项 :

4、设置用户数据:


一、简介

在 Qt 框架中,标准项模型(Standard Item Model) 是一种通用的数据模型,用于表示树形或列表结构的数据。它是 QStandardItemModel 类的实现,属于 Qt 的模型-视图架构的一部分。标准项模型提供了一种简单而灵活的方式来存储和操作数据,并与视图组件(如 QTreeViewQListViewQTableView)结合使用。


二、核心功能

  1. 模型-视图架构

    • Qt 的模型-视图架构将数据(模型)与用户界面(视图)分离。
    • 模型负责管理数据,视图负责显示数据,两者通过信号槽机制进行交互。
    • QStandardItemModel 是一个实现了 QAbstractItemModel 接口的具体模型类。
  2. 标准项模型的特点

    • 它是一个通用的、可扩展的数据模型,支持树形结构和表格结构。
    • 数据项由 QStandardItem 对象表示,每个项可以包含文本、图标、工具提示等信息。
    • 支持动态添加、删除和修改数据项。
  3. 适用场景

    • 需要快速构建简单的树形或表格视图。
    • 数据量较小且不需要复杂的自定义逻辑。
    • 适合原型开发或小型项目。

三、准备材料

注:QT的学习需要许多图片资源,如果你们缺少图片资源,建议去爱给网下载,或者让AI生成

 准备如上图片,有的是我从网上找的,有的是我用ai生成的

1、所需要的action

 2、将action添加进菜单栏里

 3、最终样式

 4、准备数据文件

一个txt文件,我这里用的是我大一的C语言作业的文件,随便弄一些数据就行


四、项目代码

1、需要用到的头文件与变量

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QStandardItemModel>
#include <QItemSelectionModel>
#include <QFileDialog>
#include <QTextStream>

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_actionOpen_triggered();

    void on_actionAdd_triggered();

    void on_actionInsert_triggered();

    void on_actionDel_triggered();

    void on_actionSee_triggered();

    void on_actionSave_triggered();

    void on_actionCenter_triggered();

    void on_actionLeft_triggered();

    void on_actionRight_triggered();

    void on_actionBold_triggered(bool checked);

    void onSelectModelCurrentChanged(const QModelIndex &current, const QModelIndex &previous);

    void on_actionItalic_triggered(bool checked);

    void on_actionUnderLine_triggered(bool checked);

private:
    void initUI();
    void initModel(QStringList lineList);

private:
    Ui::MainWindow *ui;
    QStandardItemModel* standModel;
    QItemSelectionModel* selectModel;
};
#endif // MAINWINDOW_H

2、初始化组件

void MainWindow::initUI()
{
    // 创建一个标准项模型(QStandardItemModel),并指定父对象为当前窗口(this)
    // 初始行列数设置为 0,表示模型为空
    standModel = new QStandardItemModel(0, 0, this);

    // 创建一个选择模型(QItemSelectionModel),并将其与标准项模型关联
    // 选择模型用于管理用户在视图中的选择状态
    selectModel = new QItemSelectionModel(standModel);

    // 将标准项模型设置为 tableView 的数据模型
    // 这样 tableView 就可以显示和操作标准项模型中的数据
    ui->tableView->setModel(standModel);

    // 将选择模型设置为 tableView 的选择模型
    // 这样 tableView 的选择操作(如点击、拖拽)会被记录到选择模型中
    ui->tableView->setSelectionModel(selectModel);

    // 设置 tableView 的选择模式为“扩展选择”(ExtendedSelection)
    // 扩展选择允许用户通过按住 Ctrl 或 Shift 键进行多选
    ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);

    //当选定的item改变时,触发槽函数
    connect(selectModel, SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
            this, SLOT(onSelectModelCurrentChanged(const QModelIndex &, const QModelIndex &)));
}

3、打开txt文件,并导入其中数据

void MainWindow::on_actionOpen_triggered()
{
    // 打开一个文件选择对话框,允许用户选择一个文件
    QString fileName = QFileDialog::getOpenFileName(
        this,                                               // 父窗口指针,指定对话框的父窗口
        "打开一个文件",                                       // 对话框标题,提示用户操作的目的
        QCoreApplication::applicationDirPath(),             // 默认打开的目录路径,这里是程序所在目录
        "文本数据文件(*.txt);;所有文件(*.*)");                 // 文件过滤器,限制或分类显示的文件类型

    // 如果用户取消了文件选择(返回空字符串),直接退出函数
    if (fileName.isEmpty()) {
        return;
    }

    //清除掉上一个文件的残余
    standModel->clear();
    ui->plainTextEdit->clear();

    // 创建 QFile 对象以操作选中的文件
    QFile file(fileName);

    // 尝试以只读和文本模式打开文件
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        // 如果文件无法打开(如权限不足或文件不存在),直接退出函数
        return;
    }

    // 创建 QTextStream 对象,用于从文件中读取文本内容
    QTextStream stream(&file);

    // 定义一个字符串列表,用于存储文件的每一行内容
    QStringList lineList;

    // 循环读取文件的每一行内容
    while (!stream.atEnd()) {                       // 注意:原代码中的条件 `stream.atEnd()` 是错误的,应改为 `!stream.atEnd()`
        QString line = stream.readLine();           // 读取一行文本
        lineList.append(line);                      // 将读取的行添加到字符串列表中
        ui->plainTextEdit->appendPlainText(line);   // 将读取的行追加到 plainTextEdit 中显示
    }

    // 关闭文件
    file.close();

    // 调用 initModel 函数,将读取的文件内容传递给模型进行初始化
    initModel(lineList);
}

4、初始化standModel的数据

void MainWindow::initModel(QStringList lineList)
{
    // 获取文件的第一行作为表头
    QString headLine = lineList[0];

    // 使用正则表达式分割字符串,提取表头字段
    // QRegExp("\\s+") 匹配一个或多个空白字符(包括空格、制表符等)
    // QString::SkipEmptyParts 忽略分割后产生的空字符串
    QStringList tableHead = headLine.split(QRegExp("\\s+"), QString::SkipEmptyParts);

    // 将分割后的表头字段设置为标准项模型的水平表头标签
    standModel->setHorizontalHeaderLabels(tableHead);

    // 遍历文件内容的其余行(从第二行开始)
    for (int i = 1; i < lineList.count(); i++) {
        // 对每一行使用正则表达式分割字符串,提取数据字段
        auto itemStrList = lineList[i].split(QRegExp("\\s+"), QString::SkipEmptyParts);

        // 获取当前行的数据字段数量
        int cols = itemStrList.count();

        // 创建一个 QList 存储当前行的 QStandardItem 对象
        QList<QStandardItem*> items;

        // 遍历当前行的前 (cols - 1) 个字段,创建对应的 QStandardItem 并添加到列表中
        for (int j = 0; j < cols - 1; j++) {
            QStandardItem* item = new QStandardItem(itemStrList[j]);
            items.append(item);
        }

        // 创建一个特殊的 QStandardItem,用于表示“是否毕业”字段
        QStandardItem* item = new QStandardItem("是否毕业");

        // 设置该字段为可勾选状态
        item->setCheckable(true);

        // 根据最后一列的值("是" 或 "否")设置复选框的状态
        itemStrList[cols - 1] == "是" ?
                    item->setCheckState(Qt::Checked) :
                    item->setCheckState(Qt::Unchecked);

        // 将“是否毕业”字段添加到当前行的项列表中
        items.append(item);

        // 将当前行的所有项添加到标准项模型中
        standModel->appendRow(items);
    }
}

 5、在尾部添加一行数据

void MainWindow::on_actionAdd_triggered()
{
    // 创建一个 QList 存储新行的所有 QStandardItem 对象
    QList<QStandardItem*> items;

    // 遍历模型的列数(除最后一列外),为每列创建一个默认值为“未初始化”的项
    for (int i = 0; i < standModel->columnCount() - 1; i++) {
        QStandardItem* item = new QStandardItem("未初始化");
        items.append(item);
    }

    // 创建最后一列的项,表示“是否毕业”,并设置为可勾选状态,默认未勾选
    QStandardItem* item = new QStandardItem("是否毕业");
    item->setCheckable(true);       // 设置为可勾选
    item->setCheckState(Qt::Unchecked); // 默认未勾选

    // 将最后一列的项添加到列表中
    items.append(item);

    // 将新行的所有项添加到标准项模型的末尾
    standModel->appendRow(items);

    // 清除当前的选择状态
    selectModel->clearSelection();

    // 获取新添加行的第一列索引,并将其设置为当前选择
    auto index = standModel->index(standModel->rowCount() - 1, 0);
    selectModel->setCurrentIndex(index, QItemSelectionModel::Select);
}

6、插入一行数据

void MainWindow::on_actionInsert_triggered()
{
    // 创建一个 QList 存储插入行的所有 QStandardItem 对象
    QList<QStandardItem*> items;

    // 遍历模型的列数(除最后一列外),为每列创建一个默认值为“未初始化”的项
    for (int i = 0; i < standModel->columnCount() - 1; i++) {
        QStandardItem* item = new QStandardItem("未初始化");
        items.append(item);
    }

    // 创建最后一列的项,表示“是否毕业”,并设置为可勾选状态,默认未勾选
    QStandardItem* item = new QStandardItem("是否毕业");
    item->setCheckable(true);       // 设置为可勾选
    item->setCheckState(Qt::Unchecked); // 默认未勾选

    // 将最后一列的项添加到列表中
    items.append(item);

    // 获取当前选中的索引
    auto index = selectModel->currentIndex();

    // 在当前选中行的位置插入新行
    standModel->insertRow(index.row(), items);

    // 清除当前的选择状态
    selectModel->clearSelection();

    // 将插入行设置为当前选择
    selectModel->setCurrentIndex(index, QItemSelectionModel::Select);
}

7、删除一行数据

void MainWindow::on_actionDel_triggered()
{
    // 获取当前选中的索引
    auto index = selectModel->currentIndex();

    // 如果当前选中的是最后一行,则直接删除该行
    if (index.row() == standModel->rowCount() - 1) {
        standModel->removeRow(index.row());
    } else {
        // 如果不是最后一行,则删除当前行,并保持选择状态不变
        standModel->removeRow(index.row());
        selectModel->setCurrentIndex(index, QItemSelectionModel::Select);
    }
}

8、预览模式,可以查看将要保存的状态

void MainWindow::on_actionSee_triggered()
{
    // 清空 plainTextEdit 控件中的内容,以便显示新的数据
    ui->plainTextEdit->clear();

    // 获取 standModel 模型中的行数和列数
    int row = standModel->rowCount();  // 获取模型的总行数
    int col = standModel->columnCount();  // 获取模型的总列数

    QString str;

    // 遍历模型的所有列,获取表头的内容
    for(int i = 0; i < col; i++) {
        // 获取第 i 列的表头项
        auto item = standModel->horizontalHeaderItem(i);
        // 将表头项的文本添加到字符串中,并用制表符(\t)分隔
        str += item->text() + "\t";
    }

    // 将表头信息追加到 plainTextEdit 控件中
    ui->plainTextEdit->appendPlainText(str);

    // 遍历模型的所有行(从第 1 行开始,跳过表头)
    for(int i = 1; i < row; i++) {
        // 初始化一个空字符串,用于存储当前行的数据
        str = "";

        // 遍历当前行的所有列(除最后一列外)
        for(int j = 0; j < col - 1; j++) {
            // 获取第 i 行、第 j 列的单元格数据
            auto item = standModel->item(i, j);
            // 将单元格的文本添加到字符串中,并用制表符(\t)分隔
            str += item->text() + "\t";
        }

        // 处理最后一列的数据(假设最后一列是复选框)
        if(standModel->item(i, col - 1)->checkState() == Qt::Checked) {
            // 如果复选框被选中,则在字符串中添加 "是"
            str += "是\t";
        } else {
            // 如果复选框未被选中,则在字符串中添加 "否"
            str += "否\t";
        }

        // 将当前行的数据追加到 plainTextEdit 控件中
        ui->plainTextEdit->appendPlainText(str);
    }
}

9、保存文件

 

void MainWindow::on_actionSave_triggered()
{
    //选择保存文件的完整路径
    QString fileName = QFileDialog::getSaveFileName(this,
                                                    "保存文件",
                                                    QCoreApplication::applicationDirPath(),
                                                    "文本数据文件(*.txt);;所有文件(*.*)");

    QFile file(fileName);

    if(!file.open(QIODevice::ReadWrite |
                QIODevice::Text |
                 QIODevice::Truncate))
    {
        return;
    }
    QTextStream stream(&file);

    QString str;

    // 获取 standModel 模型中的行数和列数
    int row = standModel->rowCount();  // 获取模型的总行数
    int col = standModel->columnCount();  // 获取模型的总列数

    // 遍历模型的所有列,获取表头的内容
    for(int i = 0; i < col; i++) {
        // 获取第 i 列的表头项
        auto item = standModel->horizontalHeaderItem(i);
        // 将表头项的文本添加到字符串中,并用制表符(\t)分隔
        str += item->text() + "\t\t";
    }

    stream << str << "\n";

    // 遍历模型的所有行(从第 1 行开始,跳过表头)
    for(int i = 1; i < row; i++) {
        // 初始化一个空字符串,用于存储当前行的数据
        str = "";

        // 遍历当前行的所有列(除最后一列外)
        for(int j = 0; j < col - 1; j++) {
            // 获取第 i 行、第 j 列的单元格数据
            auto item = standModel->item(i, j);
            // 将单元格的文本添加到字符串中,并用制表符(\t)分隔
            str += item->text() + "\t\t";
        }

        // 处理最后一列的数据(假设最后一列是复选框)
        if(standModel->item(i, col - 1)->checkState() == Qt::Checked) {
            // 如果复选框被选中,则在字符串中添加 "是"
            str += "是\t";
        } else {
            // 如果复选框未被选中,则在字符串中添加 "否"
            str += "否\t";
        }

        stream << str << "\n";
    }

    file.close();
}

 10、将表格内的内容居中

// 当用户触发“居中对齐”操作时调用此函数
void MainWindow::on_actionCenter_triggered()
{
    // 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
    if (!selectModel->hasSelection()) {
        return;
    }

    // 获取当前选中的所有索引(即用户在界面中选中的单元格)
    auto indexList = selectModel->selectedIndexes();

    // 遍历选中的索引列表
    for (auto& index : indexList) {
        // 根据索引从标准模型中获取对应的项(QStandardItem)
        auto* item = standModel->itemFromIndex(index);
        // 设置该项的文本对齐方式为居中对齐
        item->setTextAlignment(Qt::AlignCenter);
    }
}

11、 将表格内的内容居左

// 当用户触发“左对齐”操作时调用此函数
void MainWindow::on_actionLeft_triggered()
{
    // 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
    if (!selectModel->hasSelection()) {
        return;
    }

    // 获取当前选中的所有索引
    auto indexList = selectModel->selectedIndexes();

    // 遍历选中的索引列表
    for (auto& index : indexList) {
        // 根据索引从标准模型中获取对应的项
        auto* item = standModel->itemFromIndex(index);
        // 设置该项的文本对齐方式为左对齐,并垂直方向居中对齐
        item->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
    }
}

12、 将表格内的内容居右

// 当用户触发“右对齐”操作时调用此函数
void MainWindow::on_actionRight_triggered()
{
    // 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
    if (!selectModel->hasSelection()) {
        return;
    }

    // 获取当前选中的所有索引
    auto indexList = selectModel->selectedIndexes();

    // 遍历选中的索引列表
    for (auto& index : indexList) {
        // 根据索引从标准模型中获取对应的项
        auto* item = standModel->itemFromIndex(index);
        // 设置该项的文本对齐方式为右对齐,并垂直方向居中对齐
        item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
    }
}

13、设置字体

// 当用户触发“加粗”操作时调用此函数
void MainWindow::on_actionBold_triggered(bool checked)
{
    // 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
    if (!selectModel->hasSelection()) {
        return;
    }

    // 获取当前选中的所有索引(即用户在界面中选中的单元格)
    auto indexList = selectModel->selectedIndexes();

    // 遍历选中的索引列表
    for (auto& index : indexList) {
        // 根据索引从标准模型中获取对应的项(QStandardItem)
        auto* item = standModel->itemFromIndex(index);
        // 获取该项的字体
        QFont font = item->font();
        // 根据传入的参数 `checked` 设置字体是否加粗
        font.setBold(checked);
        // 将修改后的字体重新设置到该项
        item->setFont(font);
    }
}

// 当用户触发“斜体”操作时调用此函数
void MainWindow::on_actionItalic_triggered(bool checked)
{
    // 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
    if (!selectModel->hasSelection()) {
        return;
    }

    // 获取当前选中的所有索引
    auto indexList = selectModel->selectedIndexes();

    // 遍历选中的索引列表
    for (auto& index : indexList) {
        // 根据索引从标准模型中获取对应的项
        auto* item = standModel->itemFromIndex(index);
        // 获取该项的字体
        QFont font = item->font();
        // 根据传入的参数 `checked` 设置字体是否为斜体
        font.setItalic(checked);
        // 将修改后的字体重新设置到该项
        item->setFont(font);
    }
}

// 当用户触发“下划线”操作时调用此函数
void MainWindow::on_actionUnderLine_triggered(bool checked)
{
    // 检查是否有选中的项,如果没有选中任何项,则直接返回,不做任何操作
    if (!selectModel->hasSelection()) {
        return;
    }

    // 获取当前选中的所有索引
    auto indexList = selectModel->selectedIndexes();

    // 遍历选中的索引列表
    for (auto& index : indexList) {
        // 根据索引从标准模型中获取对应的项
        auto* item = standModel->itemFromIndex(index);
        // 获取该项的字体
        QFont font = item->font();
        // 根据传入的参数 `checked` 设置字体是否带有下划线
        font.setUnderline(checked);
        // 将修改后的字体重新设置到该项
        item->setFont(font);
    }
}

 14、当选择的标签变化时,更新字体种类

// 当选择模型的当前选中项发生变化时调用此函数
void MainWindow::onSelectModelCurrentChanged(const QModelIndex &current, const QModelIndex &previous)
{
    // 检查当前选中的索引是否有效(即是否存在有效的选中项)
    if (current.isValid()) {
        // 根据当前选中的索引从标准模型中获取对应的项(QStandardItem)
        auto* item = standModel->itemFromIndex(current);

        // 获取该项的字体,并根据字体属性更新界面上的操作按钮状态
        // 设置“加粗”操作按钮的状态为字体的加粗属性(true 或 false)
        ui->actionBold->setChecked(item->font().bold());

        // 设置“斜体”操作按钮的状态为字体的斜体属性(true 或 false)
        ui->actionItalic->setChecked(item->font().italic());

        // 设置“下划线”操作按钮的状态为字体的下划线属性(true 或 false)
        ui->actionUnderLine->setChecked(item->font().underline());
    }
}

 15、运行结果


五、常用接口

以下是 QStandardItemModelQStandardItem 的一些常用方法:

QStandardItemModel

1、设置行列数
void setRowCount(int rows);
void setColumnCount(int columns);
2、插入项:
void appendRow(QStandardItem *item);
void insertRow(int row, QStandardItem *item);
3、获取项:
QStandardItem *item(int row, int column = 0) const;
4、清除模型:
void clear();

QStandardItem

1、设置文本:
void setText(const QString &text);
QString text() const;
2、设置图标:
void setIcon(const QIcon &icon);
QIcon icon() const;
3、设置子项
void appendRow(QStandardItem *item);
void appendRows(const QList<QStandardItem *> &items);
4、设置用户数据:
void setData(const QVariant &value, int role = Qt::UserRole + 1);
QVariant data(int role = Qt::UserRole + 1) const;

相关文章:

  • 2024华为OD机试真题-数据分类算法(C++/Java/Python)-E卷-100分
  • 零基础学习OpenGL(二)查看各工程源码
  • 蓝桥杯备考:动态规划线性dp之下楼梯问题进阶版
  • MacOS 10.15上使用Docker遇到的几个问题
  • Python中的内置函数 - 第一章
  • Linux:vim快捷键
  • VBA中类的解读及应用第二十一讲:利用类方法判断任意单元格类型-4
  • 原生android 打包.aar到uniapp使用
  • 《玩转AI大模型:从入门到创新实践》(12)LLM初步(4)
  • Redis数据库面试——数据结构类型知识
  • Android Flow操作符分类
  • FastGPT 引申:Rerank 函数调用实例
  • 【Linux】【网络】UDP打洞-->不同子网下的客户端和服务器通信(成功版)
  • ArcGIS Pro 制作地理区位图的实用技巧与步骤
  • Node.js学习分享(上)
  • Python的那些事第三十九篇:MongoDB的Python驱动程序PyMongo
  • Java方法详解
  • 蓝桥杯 之 贪心与排序
  • 【经济学】第一章:经济学基础:生产、市场与宏观经济的数学透视
  • 3.多线程获取音频AI的PCM数据
  • 手机怎么做微电影网站/本周时事新闻概要10条
  • 网站建设和信息更新的通知/seo关键词选择及优化
  • 途牛网站开发需求/网站seo视频狼雨seo教程
  • 会python做网站/好用的推广平台
  • 做门户网站的系统/今日热点新闻事件简介
  • 国内ui做的好的网站/整合营销名词解释