大家好,我是小哈哥,今天我们接着上一篇网文的内容,继续完成网友问答。
今天我们来分享第三个问题的解决方案:
- 基于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");
- 设置当前进程界面不可见:
excel->dynamicCall("SetVisible(bool)", false);
- 获取工作簿集合:
QAxObject *workbooks = NULL;workbooks = excel->querySubObject("WorkBooks")
QAxObject *workbooks = NULL;
workbooks = excel->querySubObject("WorkBooks");
;
- 打开已存在的工作簿:
QAxObject *workbook = NULL;
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();
//获取起始行
int iStartRow = rows->property("Row").toInt();
- 获取列数:
QAxObject * columns = usedrange->querySubObject("Columns");
int iColumns = columns->property("Count").toInt();、
//获取起始列
int iColumn = columns->property("Column").toInt();
- 设置某单元格的值:
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、小程序,欢迎感兴趣的朋友,持续关注。