大家好,我是小哈哥,今天我們接著上一篇網文的內容,繼續完成網友問答。
今天我們來分享第三個問題的解決方案:
- 基于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、小程序,歡迎感興趣的朋友,持續關注。