C/C++中的 Qt StandardItemModel 数据模型应用解析

QStandardItemModel 是标准的以项数据为单位的基于M/V模型的一种标准数据管理方式,Model/View 是Qt中的一种数据编排结构,其中Model代表模型,View代表视图,视图是显示和编辑数据的界面组件,而模型则是视图与原始数据之间的接口,通常该类结构都是用在数据库中较多,例如模型结构负责读取或写入数据库,视图结构则负责展示数据,其条理清晰,编写代码便于维护。

QStandardItemModel组件通常会配合TableView组件一起使用,当数据库或文本中的记录发生变化时会自动同步到组件中,首先绘制UI界面。

其次绑定顶部ToolBar菜单,分别对菜单增加对应的功能属性的描述等。

初始化构造函数: 当程序运行时,我们需要对页面中的控件逐一初始化,并将Table表格与模型通过调用ui->tableView->setModel(model)进行绑定。

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <iostream>
#include <QLabel>
#include <QStandardItem>
#include <QItemSelectionModel>

#include <QFileDialog>
#include <QTextStream>

#include <QList>

// 默认构造函数
// https://www.cnblogs.com/lyshark
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 初始化部分
    model = new QStandardItemModel(3,FixedColumnCount,this);  // 数据模型初始化
    selection = new QItemSelectionModel(model);               // Item选择模型

    // 为TableView设置数据模型
    ui->tableView->setModel(model);               // 设置数据模型
    ui->tableView->setSelectionModel(selection);  // 设置选择模型

    // 默认禁用所有Action选项,只保留打开
    ui->actionSave->setEnabled(false);
    ui->actionView->setEnabled(false);
    ui->actionAppend->setEnabled(false);
    ui->actionDelete->setEnabled(false);
    ui->actionInsert->setEnabled(false);

    // 创建状态栏组件,主要来显示单元格位置
    LabCurFile = new QLabel("当前文件:",this);
    LabCurFile->setMinimumWidth(200);

    LabCellPos = new QLabel("当前单元格:",this);
    LabCellPos->setMinimumWidth(180);
    LabCellPos->setAlignment(Qt::AlignHCenter);

    LabCellText = new QLabel("单元格内容:",this);
    LabCellText->setMinimumWidth(150);

    ui->statusbar->addWidget(LabCurFile);
    ui->statusbar->addWidget(LabCellPos);
    ui->statusbar->addWidget(LabCellText);

    //选择当前单元格变化时的信号与槽
    connect(selection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

初始化时同时需要绑定一个on_currentChanged(QModelIndex,QModelIndex)信号,当用户选中指定单元格时相应用户。

// 选择单元格变化时的响应,通过在构造函数中绑定信号和槽函数实现触发
// https://www.cnblogs.com/lyshark
void MainWindow::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
   Q_UNUSED(previous);

    if (current.isValid()) //当前模型索引有效
    {
        LabCellPos->setText(QString::asprintf("当前单元格:%d行,%d列",current.row(),current.column())); //显示模型索引的行和列号
        QStandardItem   *aItem;
        aItem=model->itemFromIndex(current); //从模型索引获得Item
        this->LabCellText->setText("单元格内容:"+aItem->text()); //显示item的文字内容
    }
}

当页面被初始化时,默认界面如下:

打开并填充组件: 当工具栏中打开文件被点击后则触发,打开文件时通过aFile.open打开,循环读入文件,并将文件中的内容逐行追加到QStringList fFileContent中,当追加完毕后,直接调用iniModelFromStringList(fFileContent);完成对页面TableView组件的初始化,并设置其他控件状态为可点击。

void MainWindow::on_actionOpen_triggered()
{
    QString curPath=QCoreApplication::applicationDirPath(); // 获取应用程序的路径

    // 调用打开文件对话框打开一个文件
    // https://www.cnblogs.com/lyshark
    QString aFileName=QFileDialog::getOpenFileName(this,"打开一个文件",curPath,"数据文件(*.txt);;所有文件(*.*)");
    if (aFileName.isEmpty())
    {
        return; // 如果未选择文件则退出
    }

    QStringList fFileContent;                              // 文件内容字符串列表
    QFile aFile(aFileName);                                // 以文件方式读出
    if (aFile.open(QIODevice::ReadOnly | QIODevice::Text)) // 以只读文本方式打开文件
    {
        QTextStream aStream(&aFile);       // 用文本流读取文件
        ui->plainTextEdit->clear();        // 清空列表

        // 循环读取只要不为空
        while (!aStream.atEnd())
        {
            QString str=aStream.readLine();          // 读取文件的一行
            ui->plainTextEdit->appendPlainText(str); // 添加到文本框显示
            fFileContent.append(str);                // 添加到StringList
        }
        aFile.close();                               // 关闭文件

        iniModelFromStringList(fFileContent);        // 从StringList的内容初始化数据模型
    }

    // 打开文件完成后,就可以将Action全部开启了
    ui->actionSave->setEnabled(true);
    ui->actionView->setEnabled(true);
    ui->actionAppend->setEnabled(true);
    ui->actionDelete->setEnabled(true);
    ui->actionInsert->setEnabled(true);

    // 打开文件成功后,设置状态栏当前文件列
    this->LabCurFile->setText("当前文件:"+aFileName);//状态栏显示
}

如上iniModelFromStringList(fFileContent);函数是后期增加的,我们需要自己实现,该函数的作用是从传入的StringList中获取数据,并将数据初始化到TableView模型中,实现代码如下。

void MainWindow::iniModelFromStringList(QStringList& aFileContent)
{
    int rowCnt=aFileContent.count();     // 文本行数,第1行是标题
    model->setRowCount(rowCnt-1);        // 实际数据行数,要在标题上减去1

    // 设置表头
    QString header=aFileContent.at(0);         // 第1行是表头

    // 一个或多个空格、TAB等分隔符隔开的字符串、分解为一个StringList
    // https://www.cnblogs.com/lyshark
    QStringList headerList=header.split(QRegExp("\\s+"),QString::SkipEmptyParts);
    model->setHorizontalHeaderLabels(headerList); // 设置表头文字

    // 设置表格中的数据
    int x = 0,y = 0;
    QStandardItem *Item;

    // 有多少列数据就循环多少次
    // https://www.cnblogs.com/lyshark
    for(x=1; x < rowCnt; x++)
    {
        QString LineText = aFileContent.at(x);    // 获取数据区的一行

        // 一个或多个空格、TAB等分隔符隔开的字符串、分解为一个StringList
        QStringList tmpList=LineText.split(QRegExp("\\s+"),QString::SkipEmptyParts);

        // 循环列数,也就是循环FixedColumnCount,其中tmpList中的内容也是.
        for(y=0; y < FixedColumnCount-1; y++)
        {
            Item = new QStandardItem(tmpList.at(y)); // 创建item
            model->setItem(x-1,y,Item);              // 为模型的某个行列位置设置Item
        }

        // 最后一个数据需要取出来判断,并单独设置状态
        Item=new QStandardItem(headerList.at(y));   // 最后一列是Checkable,需要设置
        Item->setCheckable(true);                   // 设置为Checkable

        // 判断最后一个数值是否为0
        if (tmpList.at(y) == "0")
            Item->setCheckState(Qt::Unchecked);   // 根据数据设置check状态
        else
            Item->setCheckState(Qt::Checked);

        model->setItem(x-1,y,Item); //为模型的某个行列位置设置Item
    }
}

初始化组件后效果如下:

实现添加一行数据: 为TableView添加一行数据,在文件末尾插入。

void MainWindow::on_actionAppend_triggered()
{
    QList<QStandardItem *> ItemList;   // 创建临时容器
    QStandardItem *Item;

    // 模拟添加一列的数据
    for(int x=0; x<FixedColumnCount-1; x++)
    {
        Item = new QStandardItem("测试(追加行)");    // 循环创建每一列
        ItemList << Item;                          // 添加到链表中
    }

    // 创建最后一个列元素,由于是选择框所以需要单独创建
    // https://www.cnblogs.com/lyshark
    // 1.获取到最后一列的表头下标,最后下标为6
    QString str = model->headerData(model->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();

    Item=new QStandardItem(str); // 创建 "是否合格" 字段
    Item->setCheckable(true);    // 设置状态为真
    ItemList << Item;            // 最后一个选项追加进去

    model->insertRow(model->rowCount(),ItemList);                 // 插入一行,需要每个Cell的Item
    QModelIndex curIndex=model->index(model->rowCount()-1,0);     // 创建最后一行的ModelIndex

    selection->clearSelection();                                      // 清空当前选中项
    selection->setCurrentIndex(curIndex,QItemSelectionModel::Select); // 设置当前选中项为当前选择行
}

插入代码演示效果:

实现插入一行数据: 为TableView插入一行数据(在文件任意位置插入数据)

// https://www.cnblogs.com/lyshark
void MainWindow::on_actionInsert_triggered()
{
    QList<QStandardItem*> ItemList;       // QStandardItem的列表类
    QStandardItem *Item;

    // 模拟插入前五列数据
    for(int i=0;i<FixedColumnCount-1;i++)
    {
        Item= new QStandardItem("测试(插入行)");  // 新建一个QStandardItem
        ItemList << Item;                        // 添加到列表类
    }

    QString str;                               // 获取表头文字
    str=model->headerData(model->columnCount()-1,Qt::Horizontal,Qt::DisplayRole).toString();
    Item=new QStandardItem(str);      // 创建Item
    Item->setCheckable(true);         // 设置为可使用CheckBox
    ItemList<<Item;                   // 添加到列表类

    QModelIndex curIndex=selection->currentIndex(); // 获取当前选中项的索引
    model->insertRow(curIndex.row(),ItemList);      // 在当前行的前面插入一行
    selection->clearSelection();                                       // 清除当前选中项
    selection->setCurrentIndex(curIndex,QItemSelectionModel::Select);  // 设置当前选中项为当前选择行
}

插入代码演示效果:

实现删除一行数据: 删除数据之前需要通过selection->currentIndex()确定当前选中行,并通过model->removeRow()移除即可。

// https://www.cnblogs.com/lyshark
void MainWindow::on_actionDelete_triggered()
{
    QModelIndex curIndex = selection->currentIndex();  // 获取当前选择单元格的模型索引

    // 先判断是不是最后一行
    if (curIndex.row()==model->rowCount()-1)
    {
        model->removeRow(curIndex.row()); //删除最后一行
    }
    else
    {
        model->removeRow(curIndex.row());//删除一行,并重新设置当前选择行
        selection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
    }
}

删除代码效果演示:

实现字体数据对齐: 表格中的字体可以实现多种对其方式,对齐方式分为 居中对齐,左对齐,右对齐 三种。

// 设置表格居中对齐
void MainWindow::on_pushButton_clicked()
{
    if (!selection->hasSelection())
        return;

    QModelIndexList selectedIndex=selection->selectedIndexes();

    QModelIndex Index;
    QStandardItem *Item;

    for (int i=0; i<selectedIndex.count(); i++)
    {
        Index=selectedIndex.at(i);
        Item=model->itemFromIndex(Index);
        Item->setTextAlignment(Qt::AlignHCenter);
    }
}

// 设置表格左对齐
// https://www.cnblogs.com/lyshark
void MainWindow::on_pushButton_2_clicked()
{
    if (!selection->hasSelection()) //没有选择的项
        return;

//获取选择的单元格的模型索引列表,可以是多选
    QModelIndexList selectedIndex=selection->selectedIndexes();

    for (int i=0;i<selectedIndex.count();i++)
    {
        QModelIndex aIndex=selectedIndex.at(i); //获取其中的一个模型索引
        QStandardItem* aItem=model->itemFromIndex(aIndex);//获取一个单元格的项数据对象
        aItem->setTextAlignment(Qt::AlignLeft);//设置文字对齐方式
    }
}

// 设置表格右对齐
void MainWindow::on_pushButton_3_clicked()
{
    if (!selection->hasSelection())
        return;

    QModelIndexList selectedIndex=selection->selectedIndexes();

    QModelIndex aIndex;
    QStandardItem *aItem;

    for (int i=0;i<selectedIndex.count();i++)
    {
        aIndex=selectedIndex.at(i);
        aItem=model->itemFromIndex(aIndex);
        aItem->setTextAlignment(Qt::AlignRight);
    }
}

对齐代码效果演示:

实现字体数据加粗: 将选中行的字体进行加粗显示。

// 设置字体加粗显示
// https://www.cnblogs.com/lyshark
void MainWindow::on_pushButton_4_clicked()
{
    if (!selection->hasSelection())
        return;

//获取选择单元格的模型索引列表
    QModelIndexList selectedIndex=selection->selectedIndexes();

    for (int i=0;i<selectedIndex.count();i++)
    {
        QModelIndex aIndex=selectedIndex.at(i); //获取一个模型索引
        QStandardItem* aItem=model->itemFromIndex(aIndex);//获取项数据
        QFont font=aItem->font(); //获取字体
        font.setBold(true); //设置字体是否粗体
        aItem->setFont(font); //重新设置字体
    }

加粗代码效果演示:

实现保存文件: 当保存文件被点击后触发,通过便利TableWidget模型组件中的数据,并将数据通过aStream << str << "\n";写出到记事本中。

// https://www.cnblogs.com/lyshark
// 【保存文件】
void MainWindow::on_actionSave_triggered()
{
    QString curPath=QCoreApplication::applicationDirPath(); // 获取应用程序的路径

    // 调用打开文件对话框选择一个文件
    QString aFileName=QFileDialog::getSaveFileName(this,tr("选择一个文件"),curPath,"数据文件(*.txt);;所有文件(*.*)");

    if (aFileName.isEmpty()) // 未选择文件则直接退出
        return;

    QFile aFile(aFileName);

    // 以读写、覆盖原有内容方式打开文件
    if (!(aFile.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)))
        return;

    QTextStream aStream(&amp;aFile);    // 用文本流读取文件
    QStandardItem *Item;
    QString str;
    int x = 0,y = 0;

    ui-&gt;plainTextEdit-&gt;clear();

// 获取表头文字
    for (x=0; x&lt;model-&gt;columnCount(); x++)
    {
        Item=model-&gt;horizontalHeaderItem(x);     // 获取表头的项数据
        str= str + Item-&gt;text() + "\t\t";        // 以TAB制表符隔开
    }
    aStream &lt;&lt; str &lt;&lt; "\n";                      // 文件里需要加入换行符\n
    ui-&gt;plainTextEdit-&gt;appendPlainText(str);

// 获取数据区文字
    for ( x=0; x &lt; model-&gt;rowCount(); x++)
    {
        str = "";
        for( y=0; y &lt; model-&gt;columnCount()-1; y++)
        {
            Item=model-&gt;item(x,y);
            str=str + Item-&gt;text() + QString::asprintf("\t\t");
        }

        // 对最后一列需要转换一下,如果判断为选中则写1否则写0
        Item=model-&gt;item(x,y);
        if (Item-&gt;checkState()==Qt::Checked)
            str= str + "1";
        else
            str= str + "0";

         ui-&gt;plainTextEdit-&gt;appendPlainText(str);
         aStream &lt;&lt; str &lt;&lt; "\n";
    }
}

// 【导出Txt文件】:将TableView中的数据导出到PlainTextEdit显示
void MainWindow::on_actionView_triggered()
{
        ui-&gt;plainTextEdit-&gt;clear();
        QStandardItem *Item;
        QString str;

    //获取表头文字
        int x=0,y=0;
        for (x=0; x&lt;model-&gt;columnCount(); x++)
        { //
            Item=model-&gt;horizontalHeaderItem(x);
            str= str + Item-&gt;text() + "\t";
        }
        ui-&gt;plainTextEdit-&gt;appendPlainText(str);

    //获取数据区的每行
        for (x=0; x&lt;model-&gt;rowCount(); x++)
        {
            str="";
            for(y=0; y&lt;model-&gt;columnCount()-1; y++)
            {
                Item=model-&gt;item(x,y);
                str= str + Item-&gt;text() + QString::asprintf("\t");
            }

            Item=model-&gt;item(x,y);
            if (Item-&gt;checkState()==Qt::Checked)
                str= str + "1";
            else
                str= str + "0";

             ui-&gt;plainTextEdit-&gt;appendPlainText(str);
        }
}

文件保存后如下:

到此这篇关于C/C++中的 Qt StandardItemModel 数据模型应用解析的文章就介绍到这了,更多相关C++ Qt StandardItemModel 数据模型内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C/C++ Qt TabWidget 实现多窗体创建详解

    在开发窗体应用时通常会伴随分页,TabWidget组件配合自定义Dialog组件,可实现一个复杂的多窗体分页结构,此类结构也是ERP等软件通用的窗体布局方案. 首先先来实现一个只有TabWidget分页的简单结构,如下窗体布局,布局中空白部分是一个TabWidget组件,下方是一个按钮,当用户点击按钮时,自动将该窗体新增到TabWidget组件中. 该页面关联代码如下所示,当用户点击on_pushButton_clicked()时自动新增一个窗体并将窗体的Tab设置为指定的IP地址. t->se

  • C/C++ Qt StringListModel 字符串列表映射组件详解

    StringListModel 字符串列表映射组件,该组件用于处理字符串与列表框组件中数据的转换,通常该组件会配合ListView组件一起使用,例如将ListView组件与Model模型绑定,当ListView组件内有数据更新时,我们就可以利用映射将数据模型中的数值以字符串格式提取出来,同理也可实现将字符串赋值到指定的ListView组件内. 首先在UI界面中排版 默认的MainWindow::MainWindow构造函数中,我们首先初始化一个QStringList字符串链表并对该链表赋值,通过

  • C/C++ Qt TableDelegate 自定义代理组件使用详解

    TableDelegate 自定义代理组件的主要作用是对原有表格进行调整,例如默认情况下Table中的缺省代理就是一个编辑框,我们只能够在编辑框内输入数据,而有时我们想选择数据而不是输入,此时就需要重写编辑框实现选择的效果,代理组件常用于个性化定制Table表格中的字段类型. 在自定义代理中QAbstractItemDelegate是所有代理类的抽象基类,我们继承任何组件时都必须要包括如下4个函数: CreateEditor() 用于创建编辑模型数据的组件,例如(QSpinBox组件) SetE

  • C/C++ Qt StatusBar底部状态栏应用教程

    Qt窗体中默认会附加一个QstatusBar组件,状态栏组件位于主窗体的最下方,其作用是提供一个工具提示功能,当程序中有提示信息是可以动态的显示在这个区域内,状态栏组件内可以增加任何Qt中的通用组件,只需要通过addWidget函数动态追加即可引入到底部,底部状态栏在实际开发中应用非常普遍,以下代码是对该组件基本使用方法的总结. 首先我们通过new新增3个QLabel组件,并将该组件依次排列在底部状态栏内,实现代码如下所示: #include "mainwindow.h" #inclu

  • C/C++中的 Qt StandardItemModel 数据模型应用解析

    QStandardItemModel 是标准的以项数据为单位的基于M/V模型的一种标准数据管理方式,Model/View 是Qt中的一种数据编排结构,其中Model代表模型,View代表视图,视图是显示和编辑数据的界面组件,而模型则是视图与原始数据之间的接口,通常该类结构都是用在数据库中较多,例如模型结构负责读取或写入数据库,视图结构则负责展示数据,其条理清晰,编写代码便于维护. QStandardItemModel组件通常会配合TableView组件一起使用,当数据库或文本中的记录发生变化时会

  • MFC程序中使用QT开发界面的实现步骤

    目录 添加QT依赖 添加信号槽机制 添加qt界面 配置元编译过程 一些问题的处理 测试信号槽 使用qt designer 设计界面 如果你有一个现成的MFC项目在做维护,但是你厌倦了使用MFC繁琐的操作来做界面美化,或者你需要在这个项目中用到QT里面好用的某些功能:亦或者是你需要使用某些只能在MFC中使用的组件,但是界面这部分已经用QT做好了.那么这篇文章可能可以帮助到你 演示环境使用Visual Studio 2019 + QT5.12.8 版本 添加QT依赖 首先创建一个基于对话框的MFC工

  • Python3 中作为一等对象的函数解析

    Python3 函数 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可以自己创建函数,这被叫做用户自定义函数. 在 Python 语言中,函数与整数.字符串.字典等基本数据类型一样,都是 一等对象 .所谓一等对象,即满足如下三个条件: 在运行时创建 能赋值给变量 能作为函数的参数或返回值 以下 IDLE 中的代码即在运行时创建了函数 factorial : >>

  • QT .pro文件使用解析

    目录 1.pro文件的作用 2.一个简单的示例 3.指定链接的三方库 4.编译为库 5.指定debug,release,win32平台还是别的平台 6.判断编译环境是x86架构还是arm架构 7.在linux下编译后指定make install后的文件路径 1.pro文件的作用 QT工程的pro文件,在创建工程时由QTCreater自动创建,我们可以往里面添加内容,增加库文件的声明,包含路径.预处理器定义,生成目录,输出中间目录等等设置. 2.一个简单的示例 QT+= core gui char

  • Qt利用QJson实现解析数组的示例详解

    目录 前言 第一步:进行数据转换 第二步:将字符串转成QJsonDocument格式 第三步:解析json数据 前言 现在有这样一个json结构,需要使用QJson来解析,结构如下: "code": "0001", "descrip": "文本描述1详细描述", "id": "1", "title": "文本1标题", "type&quo

  • 在AngularJS框架中处理数据建模的方式解析

    我们知道,AngularJS并没有自带立等可用的数据建模方案.而是以相当抽象的方式,让我们在controller中使用JSON数据作为模型.但是随着时间的推移和项目的成长,我意识到这种建模的方式不再能满足我们项目的需求.在这篇文章中我会介绍在我的AngularJS应用中处理数据建模的方式. 为Controller定义模型 让我们从一个简单的例子开始.我想要显示一个书本(book)的页面.下面是控制器(Controller): BookController app.controller('Book

  • mysql查询语句中用户变量的使用代码解析

    上一篇文章中我们介绍了MySQL优化总结-查询总条数.这篇文章我们来介绍下查询语句中的另一个知识:用户变量的使用代码解析. 先上代码吧 SELECT `notice`.`id` , `notice`.`fid` , `notice`.`has_read` , `notice`.`notice_time` , `notice`.`read_time` , `f`.`fnum` , `f`.`forg` , `f`.`fdst` , `f`.`actual_parking` AS `parking`

  • Sql Server中Substring函数的用法实例解析

    SQL 中的 substring 函数是用来抓出一个栏位资料中的其中一部分.这个函数的名称在不同的资料库中不完全一样: MySQL: SUBSTR( ), SUBSTRING( ) Oracle: SUBSTR( ) SQL Server: SUBSTRING( ) SQL 中的 substring 函数是用来截取一个栏位资料中的其中一部分. 例如,我们需要将字符串'abdcsef'中的'abd'给提取出来,则可用substring 来实现: select substring('abdcsef'

  • JavaScript中原型链存在的问题解析

    我们知道使用原型链实现继承是一个goodway:)看个原型链继承的例子. function A () { this.abc = 44; } A.prototype.getAbc = function (){ return this.abc; }; function B() { } B.prototype = new A(); // B通过A的实例完成了继承,形成了原型链(B的原型就是A的实例) var b = new B(); b.getAbc(); 关系如下:b(实例) ->B.prototy

  • 在 Node.js 中使用原生 ES 模块方法解析

    从版本 8.5.0 开始,Node.js 开始支持原生 ES 模块,可以通过命令行选项打开该功能.新功能很大程度上得归功于 Bradley Farias. 1.演示 这个示例的代码目录结构如下: esm-demo/ lib.mjs main.mjs lib.mjs: export function add(x, y) { return x + y; } main.mjs: import {add} from './lib.mjs'; console.log('Result: '+add(2, 3

随机推荐