干货|使用Qt将采集到的结果数据保存至Excel中

大家好,我是小哈哥,今天我们接着上一篇网文的内容,继续完成网友问答

今天我们来分享第三个问题的解决方案:

  • 基于Modbus协议将电压数据上传至上位机
  • Qt程序解析Modbus协议,并将解析之后的结果显示在曲线中
  • 将声音强度数据保存至Excel中

本次分享的实例在 分享一个非常强大且好用的绘图控件QCustomPlot 的程序基础上完成。

要解决这个问题,我们要先了解一下,什么是VBA

VBA

很多人听过大名鼎鼎的VBA,至于怎么用可能不太熟悉,那么VBA是什么呢?

VBA(Visual Basic for Applications)是Visual Basic的一种宏语言,是在其桌面应用程序中执行通用的自动化(OLE)任务的编程语言。主要能用来扩展Windows的应用程序功能,特别是Microsoft Office软件。它也可说是一种应用程式视觉化的 Basic 脚本。

Office取得巨大成功的一个重要原因就是VBA,使用VBA可以完成很多事情,基于Excel、Word的VBA小程序不计其数。掌握对VBA语言的使用,可以让复杂的工作简易化,减少不必要的重复性工作,大大提高我们的工作效率。

VBA 是基于Visual Basic 发展而来的,它们具有相似的语言结构。

我们来一个VBA小程序

VBA是依附于Office的。

在新工作表的Sheet1上点击右键,弹出菜单中选择“查看代码”。

或者直接使用快捷键 Alt+F11 ,打开VBA编辑器:

在编辑框中写入如下代码:

Sub TestDemo()
    MsgBox ("Hello world")
End Sub

我们点击运行按钮,可以查看此过程的运行结果。

这样我们的第一个VBA程序就完成了。

将上面的过程改成函数,我们还可以在单元格的双击事件中调用该函数,具体代码如下:

Function TestDemo()
    MsgBox ("Hello world")
End Function

Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, Cancel As Boolean)
    ' Call TestDemo
    Application.Run TestDemo()
End Sub

这样,我们在Excel中,双击单元格,就可以弹出内容为Hello world的对话框了,具体演示效果如下:

VBA中的过程(Procedure)有两种,它们都是一个可以获取参数、执行一系列语句、以及改变其参数的值的独立过程。

一种叫函数(Function)           '可调用代码block 

一种叫子程序(Subroutine)    '可执行代码block

VBA操作Excel单元格

目标:生成一个Excel,然后修改Sheet的名字并让单元格内填充内容,具体演示效果如下:

涉及的完整代码如下:

Sub AddWorkbooks()
    Set wb = Workbooks.Add
    Set ws = wb.Sheets(1)
    ws.Name = "嵌入式从0到1"
    ws.Cells(1, 1) = "序号"
    ws.Cells(1, 2) = "声音强度"
    For i = 2 To 10
        ws.Cells(i, 1) = i - 1
    Next i
    ActiveWorkbook.SaveAs Filename:=ThisWorkbook.Path & Application.PathSeparator & "test.xlsx", FileFormat:=xlOpenXMLWorkbook
    ActiveWindow.Close
End Sub

.xlsx文件为什么不能保存VBA代码呢?

2003版(.xls文件)可以保存带VBA代码的文件,不用更改扩展名。但是,当你要运行宏时,必须在安全性设置里启用宏,比较麻烦。2007版以上进行了改进,可以直接把带VBA代码的文件另存为.xlsm文件。这样,打开这个文件,可以直接运行宏。

.xlsx文件保存带有VBA代码的文件会有提示,将此文件另存为.xlsm文件即可避免提示。

.xlsm文件是“启用宏的工作簿”,也就是含有VBA代码的表格。

Qt的Excel操作常用类

在VBA的参考手册中就可以看到具体函数、属性的用法,Qt操作Excel主要通过 QAxObject + Excel VBA来实现!

QAxObject *excel = NULL;
excel = new QAxObject("Excel.Application");
  1. 设置当前进程界面不可见:
excel->dynamicCall("SetVisible(bool)", false);
  1. 获取工作簿集合:
QAxObject *workbooks = NULL;workbooks = excel->querySubObject("WorkBooks")
QAxObject *workbooks = NULL;
workbooks = excel->querySubObject("WorkBooks");
;
  1. 打开已存在的工作簿:
QAxObject *workbook = NULL;
QString templateFilePath = qApp->applicationDirPath() + "/template.xlsx";
workbook = workbooks->querySubObject("Open(QString&)",templateFilePath);
  1. 获取所有的工作表:
QAxObject * worksheets = workbook->querySubObject("WorkSheets");
  1. 获取第一个工作表:
QAxObject * worksheet = worksheets->querySubObject("Item(int)", 1);
  1. 获取表范围:
QAxObject * usedrange = worksheet->querySubObject("UsedRange");
  1. 获取行数:
QAxObject * rows = usedrange->querySubObject("Rows");    
int iRows = rows->property("Count").toInt();
//获取起始行
int iStartRow = rows->property("Row").toInt();
  1. 获取列数:
QAxObject * columns = usedrange->querySubObject("Columns");    
int iColumns = columns->property("Count").toInt();、
//获取起始列
int iColumn = columns->property("Column").toInt();
  1. 设置某单元格的值:
QString cora = "A" + QString::number(iStartRow+iRows+i);        
QAxObject *rangea = worksheet->querySubObject("Range(QString)", cora);        
rangea->setProperty("Value", arrX[i]);

将声音强度保存至Excel中

首先需要在pro文件中添加axcontainer

QT += core gui printsupport axcontainer
QT += serialport

然后添加包含文件

#include <QAxObject>

如下是代码的具体实现:

void MainWindow::on_btnExportData_clicked()
{
    QAxObject *excel = NULL;
    QAxObject *workbooks = NULL;
    QAxObject *workbook = NULL;
    excel = new QAxObject("Excel.Application");
    excel->dynamicCall("SetVisible(bool)", false);
    workbooks = excel->querySubObject("WorkBooks");

    QString templateFilePath = qApp->applicationDirPath() + "/template.xlsx";

    workbook = workbooks->querySubObject("Open(QString&)",templateFilePath);

    //获取活动工作簿
    QAxObject * worksheets = workbook->querySubObject("WorkSheets");        //获取所有的工作表

    QAxObject * worksheet = worksheets->querySubObject("Item(int)", 1);

    //表格范围和行数列数
    QAxObject * usedrange = worksheet->querySubObject("UsedRange");

    QAxObject * rows = usedrange->querySubObject("Rows");
    int iRows = rows->property("Count").toInt();

    QAxObject * columns = usedrange->querySubObject("Columns");
    int iColumns = columns->property("Count").toInt();

    int iStartRow = rows->property("Row").toInt();

    int iColumn = columns->property("Column").toInt();

    //写入数据
    for(int i = 0;i<arrY.size();i++)
    {
        QString cora = "A" + QString::number(iStartRow+iRows+i);
        QAxObject *rangea = worksheet->querySubObject("Range(QString)", cora);
        rangea->setProperty("Value", arrX[i]);

        QString corb = "B" + QString::number(iStartRow+iRows+i);
        QAxObject *rangeb = worksheet->querySubObject("Range(QString)", corb);
        rangeb->setProperty("Value", arrY[i]);
    }

    workbook->dynamicCall("Save()");   //!保存文件
    workbook->dynamicCall("Close()");
    excel->dynamicCall("Quit()");

    if (excel)
    {
        delete excel;
        excel = NULL;
    }

    QMessageBox::information(0 ,"提示" ,"数据保存成功", QMessageBox::Ok | QMessageBox::Default , 0 );
}

结果展示

本实例实现的功能是打开一个模板文件,把传入的数据写到指定的单元格,并自动完成保存和关闭的操作。

下次导出的数据会追加到上次导出数据的尾部。

具体演示效果如下:

对于简单的数据保存,可以使用 .csv 文件,操作简单。如果想要使用Excel的复杂功能,可以使用本文的方法进行操作。

欢迎关注

关注公众号:嵌入式从0到1,第一时间获取技术干货,玩模块、学硬件,带你从0走到1,欢迎关注!

公众号内容包括但不限于STM32、单片机、物联网、鸿蒙、Qt、小程序,欢迎感兴趣的朋友,持续关注。

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 3
收藏 4
关注 65
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧