赞
踩
C++中有三种常用的操作Excel的方式,Xlnt、QtXlsx以及QAxObject
本文使用QAxObject来新建并保存Excel表格
1:初始化Excel程序
/*初始化Excel对象*/ QAxObject *_excelObject = NULL; ///< 代表了EXCEL服务器, QAxObject *_curWorkbook; ///< 当前工作簿 QAxObject *_curWorkSheet; ///< 当前sheet(实际就是第一个sheet) QAxObject *_usedRange; ///< sheet里的数据区域范围 /*初始化服务,否则报错误 CoCreateInstance failure <CoInitialize has not been called.> QAxBase::setControl: requested control Excel.Application could not be instantiated QAxBase::dynamicCallHelper: Object is not initialized, or initialization failed */ HRESULT r = OleInitialize(0); if (r != S_OK && r != S_FALSE) { return -1; } if (_excelObject == NULL) { /*代表整个 Microsoft Excel 应用程序。*/ _excelObject = new QAxObject("Excel.Application"); if (!_excelObject) { return -1; } }
2:隐藏Excel窗口
/*隐藏Excel窗口*/
_excelObject->setProperty("Visible", false);
3:新建一个Excel
/*返回一个表示所有打开的工作簿的**工作簿** 集合。 此为只读属性*/ QAxObject * workbooks = _excelObject->querySubObject("WorkBooks"); /*打开存在的Excel文件*/ //workbooks->dynamicCall("Open (const QString&)", "D:/123.xlsx"); /*新建一个工作表。 新工作表将成为活动工作表。*/ workbooks->dynamicCall("Add"); /*workbooks必须指向活跃 WorkBook,否则保存时报错: QAxBase::dynamicCallHelper: SaveCopyAs(QString): No such property in [unknown] Candidates are:*/ workbooks = _excelObject->querySubObject("ActiveWorkBook"); // ToDo ... /*活动工作表*/ _curWorkbook = _excelObject->querySubObject("ActiveWorkBook"); /*第一个sheet*/ _curWorkSheet = _curWorkbook->querySubObject("Worksheets(int)", 1);///< 当前sheet(实际就是第一个sheet)
3:常用操作
快速填充数据块
/*快速填充数据块, 填充B1到C20这一数据块*/
/*https://www.cnblogs.com/lifexy/p/10743316.html*/
QAxObject *user_range = _curWorkSheet->querySubObject("Range(const QString&)", cols_range);
QList<QList<QVariant> > datas;
for (int i = 0; i<20; i++)
{
QList<QVariant> rows;
rows.append(i);
rows.append(3 * i + 0.1);
datas.append(rows);
}
QVariant var;
castListListVariant2Variant(datas, var);
user_range->setProperty("Value", var);
设置单个单元格的数据和颜色
/*设置单个单元格的内容,第5行,第1列填入字符串‘Hello’*/
QAxObject *singleCell = _curWorkSheet->querySubObject("Cells(int,int)", 5, 1);
singleCell->dynamicCall("SetValue(const QVariant&)", QVariant(QStringLiteral("Hello")));
/*设置背景色为红色:http://blog.sina.com.cn/s/blog_a6fb6cc90101gv2p.html*/
QAxObject* interior = singleCell->querySubObject("Interior");
interior->setProperty("Color", QColor(0, 255, 0)); //设置单元格背景色(绿色)
使用批量公式
/*使用批量公式:https://github.com/muellerj/hexplorer/blob/master/src/excel.cpp*/ const int average_use_cnt = 100; cols_range.sprintf("E%d:E%d", 1, 20); QAxObject *user_range_formular = _curWorkSheet->querySubObject("Range(const QString&)", cols_range); QList<QList<QVariant> > datas_formular; for (int i = 0; i<19; i++) { QList<QVariant> rows; QString formular; //formular.sprintf("=RC[-2]*100"); formular.sprintf("=AVERAGE(RC[-2]:R[1]C[-2])"); rows.append(formular); datas_formular.append(rows); } QVariant var_formular; castListListVariant2Variant(datas_formular, var_formular); user_range_formular->setProperty("Value", var_formular);
添加折线图
/*画折线图*/ // 先选中一个空白的地方,不然后面的SeriesCollection会先将所有行都做个散点图。。。 _usedRange = _curWorkSheet->querySubObject("UsedRange"); QAxObject *clos = _usedRange->querySubObject("Columns"); QAxObject *emptyCell = _curWorkSheet->querySubObject("Cells(int,int)", 1, clos->property("Count").toInt() + 3); emptyCell->dynamicCall("Select(void)"); /*表达式。AddChart2(Style、 XlChartType、 Left、 Top、 Width、 Height、 NewLayout)*/ QAxObject *shapes = _curWorkSheet->querySubObject("Shapes"); shapes->dynamicCall("AddChart(int)", 74, 100, 100, 500, 800); //74:折线散点图,左 上 宽 高 // 再将视野拖回到左上角区域 QAxObject *range = _curWorkSheet->querySubObject("Range(QVariant)", "$A$1:$A$2"); range->dynamicCall("Select(void)"); int nbChart = shapes->property("Count").toInt(); QAxObject *shape = shapes->querySubObject("Range(int)", nbChart); /*根据指定的系数缩放图形宽度。 对于图片和 OLE 对象,您可以说明是相对于原始大小还是相对于当前大小缩放形状。 图片和 OLE 对象以外的形状总是相对于当前宽度缩放。*/ //shape->dynamicCall("ScaleWidth(QVariant,QVariant)",2,0); shape->dynamicCall("Select(void)"); QAxObject *chart = _curWorkbook->querySubObject("ActiveChart"); QAxObject *seriesCollection = chart->querySubObject("SeriesCollection()"); seriesCollection->dynamicCall("NewSeries (void)"); int nb = seriesCollection->property("Count").toInt(); QAxObject *series = chart->querySubObject("SeriesCollection(int)", nb); series->setProperty("Name", "Linear parameter"); /*x轴最大最小值*/ QAxObject* aixs_x = chart->querySubObject("Axes(int)", 1); aixs_x->setProperty("MinimumScale", 0); aixs_x->setProperty("MaximumScale", 25); /*y轴最大最小值*/ QAxObject* aixs_y = chart->querySubObject("Axes(int)", 2); aixs_y->setProperty("MinimumScale", 0); aixs_y->setProperty("MaximumScale", 80); // 给图表添加数据 //range->dynamicCall("Select(void)"); cols_range.sprintf("B%d:B%d", 1, 20);/*B1:C20*/ QAxObject * xvalues = _curWorkSheet->querySubObject("Range(const QString&)", cols_range); cols_range.sprintf("C%d:C%d", 1, 20);/*B1:C20*/ QAxObject * yvalues = _curWorkSheet->querySubObject("Range(const QString&)", cols_range); series->setProperty("XValues", xvalues->asVariant()); series->setProperty("Values", yvalues->asVariant());
添加趋势线
// 添加趋势线 QAxObject *trendLines = series->querySubObject("Trendlines()"); if (trendLines) { trendLines->dynamicCall("Add()"); int nbTrendLines = trendLines->property("Count").toInt(); QAxObject *trendLine = series->querySubObject("Trendlines(int)", nbTrendLines); // 设定图标格式为 “散点图”,数字-4133来自 枚举变量 XlTrendlineType : xlLogarithmic /*各种变量的值和属性名的关系:http://mugiseyebrows.ru/excel/Excel.Range.html#Cells*/ trendLine->setProperty("Type", -4132); trendLine->setProperty("Name", "TrendLineName"); trendLine->setProperty("DisplayEquation", true);/*显示公式,显示R2*/ trendLine->setProperty("DisplayRSquared",true); /*获取公式*/ QAxObject *dataLabel = trendLine->querySubObject("DataLabel"); QString strFormula = dataLabel->property("Formula").toString(); getFormulaCoeffcient_kx_plus_b(strFormula, out_k, out_b); out_formular = strFormula.toStdString(); } /*将公式中的值自动填入,但是不能随着图表选择的数据范围动态刷新*/ QAxObject *kvalue_Cell = _curWorkSheet->querySubObject("Cells(int,int)", 1, 7); QString formular; formular.sprintf("=INDEX(LINEST(R1C3:R20C3,R1C2:R20C2),1)");/*注意:Y值在左,X值在右,绝对位置*/ kvalue_Cell->setProperty("Formula", formular); QAxObject *bvalue_Cell = _curWorkSheet->querySubObject("Cells(int,int)", 2, 7); formular.sprintf("=INDEX(LINEST(R1C3:R20C3,R1C2:R20C2),2)");/*注意:Y值在左,X值在右,绝对位置*/ bvalue_Cell->setProperty("Formula", formular);
保存并退出Excel
/* ./ 会将文件保存在我的文档目录下面*/
QString filepath = "./test.xlsx";
/*文件名字转换,否则Excel一直卡住,QDir::toNativeSeparators*/
workbooks->dynamicCall("SaveCopyAs(QString)", QDir::toNativeSeparators(filepath));
/*在关闭Excel之前先调用这个不显示警告框,否则会弹出是否保存sheet1的对话框*/
_excelObject->setProperty("DisplayAlerts", false);
_excelObject->dynamicCall("Quit()");
main.cpp
#include <QAxObject> #include <QDebug> #include <QDir> #include <QColor> #include <ole2.h> #include <utility> #include "iostream" #include "stdio.h" using namespace std; //! 形如:"y = -9.113x + 78.016" //! 则 a=-9.113 b=78.016 void getFormulaCoeffcient_kx_plus_b(QString strFormula, double &k, double &b) { int posEqual = strFormula.indexOf('='); int posX = strFormula.indexOf('x'); QString strK = strFormula.mid(posEqual + 1, posX - posEqual - 1); if (strK == " ") k = 1; else k = strK.toDouble(); bool isPositive = true; QString str_after_x = strFormula.mid(posX + 1); int posB = str_after_x.indexOf('+'); if (posB == -1) { isPositive = false; posB = str_after_x.indexOf('-'); } else { isPositive = true; } if (-1 == posB) { b = 0; } else { QString strB = str_after_x.mid(posB + 1); b = strB.toDouble(); if (!isPositive) b *= -1.0; } } //把QList<QList<QVariant> > 转为QVariant,用于快速写入的 void castListListVariant2Variant(const QList<QList<QVariant> > &cells, QVariant &res) { QVariantList vars; const int rows = cells.size(); for (int i = 0; i<rows; ++i) { vars.append(QVariant(cells[i])); } res = QVariant(vars); } int main() { std::string out_formular; double out_k; double out_b; /*初始化Excel对象*/ QAxObject *_excelObject = NULL; ///< 代表了EXCEL服务器, QAxObject *_curWorkbook; ///< 当前工作簿 QAxObject *_curWorkSheet; ///< 当前sheet(实际就是第一个sheet) QAxObject *_usedRange; ///< sheet里的数据区域范围 /*初始化服务,否则报错误 CoCreateInstance failure <CoInitialize has not been called.> QAxBase::setControl: requested control Excel.Application could not be instantiated QAxBase::dynamicCallHelper: Object is not initialized, or initialization failed */ HRESULT r = OleInitialize(0); if (r != S_OK && r != S_FALSE) { return -1; } if (_excelObject == NULL) { /*代表整个 Microsoft Excel 应用程序。*/ _excelObject = new QAxObject("Excel.Application"); if (!_excelObject) { return -1; } } /*隐藏Excel窗口*/ _excelObject->setProperty("Visible", false); /*返回一个表示所有打开的工作簿的**工作簿** 集合。 此为只读属性*/ QAxObject * workbooks = _excelObject->querySubObject("WorkBooks"); /*打开存在的Excel文件*/ //workbooks->dynamicCall("Open (const QString&)", "D:/123.xlsx"); /*新建一个工作表。 新工作表将成为活动工作表。*/ workbooks->dynamicCall("Add"); /*workbooks必须指向活跃 WorkBook,否则保存时报错: QAxBase::dynamicCallHelper: SaveCopyAs(QString): No such property in [unknown] Candidates are:*/ workbooks = _excelObject->querySubObject("ActiveWorkBook"); // ToDo ... /*活动工作表*/ _curWorkbook = _excelObject->querySubObject("ActiveWorkBook"); /*第一个sheet*/ _curWorkSheet = _curWorkbook->querySubObject("Worksheets(int)", 1);///< 当前sheet(实际就是第一个sheet) QList<QVariant> listXValues, listValues; QString cols_range;/* "B1:C20" */ cols_range.sprintf("B%d:C%d", 1, 20); /*快速填充数据块, 填充B1到C20这一数据块*/ /*https://www.cnblogs.com/lifexy/p/10743316.html*/ QAxObject *user_range = _curWorkSheet->querySubObject("Range(const QString&)", cols_range); QList<QList<QVariant> > datas; for (int i = 0; i<20; i++) { QList<QVariant> rows; rows.append(i); rows.append(3 * i + 0.1); datas.append(rows); } QVariant var; castListListVariant2Variant(datas, var); user_range->setProperty("Value", var); /*设置单个单元格的内容,第5行,第1列填入字符串‘Hello’*/ QAxObject *singleCell = _curWorkSheet->querySubObject("Cells(int,int)", 5, 1); singleCell->dynamicCall("SetValue(const QVariant&)", QVariant(QStringLiteral("Hello"))); /*设置背景色为红色:http://blog.sina.com.cn/s/blog_a6fb6cc90101gv2p.html*/ QAxObject* interior = singleCell->querySubObject("Interior"); interior->setProperty("Color", QColor(0, 255, 0)); //设置单元格背景色(绿色) /*使用批量公式:https://github.com/muellerj/hexplorer/blob/master/src/excel.cpp*/ const int average_use_cnt = 100; cols_range.sprintf("E%d:E%d", 1, 20); QAxObject *user_range_formular = _curWorkSheet->querySubObject("Range(const QString&)", cols_range); QList<QList<QVariant> > datas_formular; for (int i = 0; i<19; i++) { QList<QVariant> rows; QString formular; //formular.sprintf("=RC[-2]*100"); formular.sprintf("=AVERAGE(RC[-2]:R[1]C[-2])"); rows.append(formular); datas_formular.append(rows); } QVariant var_formular; castListListVariant2Variant(datas_formular, var_formular); user_range_formular->setProperty("Value", var_formular); /*画折线图*/ // 先选中一个空白的地方,不然后面的SeriesCollection会先将所有行都做个散点图。。。 _usedRange = _curWorkSheet->querySubObject("UsedRange"); QAxObject *clos = _usedRange->querySubObject("Columns"); QAxObject *emptyCell = _curWorkSheet->querySubObject("Cells(int,int)", 1, clos->property("Count").toInt() + 3); emptyCell->dynamicCall("Select(void)"); /*表达式。AddChart2(Style、 XlChartType、 Left、 Top、 Width、 Height、 NewLayout)*/ QAxObject *shapes = _curWorkSheet->querySubObject("Shapes"); shapes->dynamicCall("AddChart(int)", 74, 100, 100, 500, 800); //74:折线散点图,左 上 宽 高 // 再将视野拖回到左上角区域 QAxObject *range = _curWorkSheet->querySubObject("Range(QVariant)", "$A$1:$A$2"); range->dynamicCall("Select(void)"); int nbChart = shapes->property("Count").toInt(); QAxObject *shape = shapes->querySubObject("Range(int)", nbChart); /*根据指定的系数缩放图形宽度。 对于图片和 OLE 对象,您可以说明是相对于原始大小还是相对于当前大小缩放形状。 图片和 OLE 对象以外的形状总是相对于当前宽度缩放。*/ //shape->dynamicCall("ScaleWidth(QVariant,QVariant)",2,0); shape->dynamicCall("Select(void)"); QAxObject *chart = _curWorkbook->querySubObject("ActiveChart"); QAxObject *seriesCollection = chart->querySubObject("SeriesCollection()"); seriesCollection->dynamicCall("NewSeries (void)"); int nb = seriesCollection->property("Count").toInt(); QAxObject *series = chart->querySubObject("SeriesCollection(int)", nb); series->setProperty("Name", "Linear parameter"); /*x轴最大最小值*/ QAxObject* aixs_x = chart->querySubObject("Axes(int)", 1); aixs_x->setProperty("MinimumScale", 0); aixs_x->setProperty("MaximumScale", 25); /*y轴最大最小值*/ QAxObject* aixs_y = chart->querySubObject("Axes(int)", 2); aixs_y->setProperty("MinimumScale", 0); aixs_y->setProperty("MaximumScale", 80); // 给图表添加数据 //range->dynamicCall("Select(void)"); cols_range.sprintf("B%d:B%d", 1, 20);/*B1:C20*/ QAxObject * xvalues = _curWorkSheet->querySubObject("Range(const QString&)", cols_range); cols_range.sprintf("C%d:C%d", 1, 20);/*B1:C20*/ QAxObject * yvalues = _curWorkSheet->querySubObject("Range(const QString&)", cols_range); series->setProperty("XValues", xvalues->asVariant()); series->setProperty("Values", yvalues->asVariant()); // 添加趋势线 QAxObject *trendLines = series->querySubObject("Trendlines()"); if (trendLines) { trendLines->dynamicCall("Add()"); int nbTrendLines = trendLines->property("Count").toInt(); QAxObject *trendLine = series->querySubObject("Trendlines(int)", nbTrendLines); // 设定图标格式为 “散点图”,数字-4133来自 枚举变量 XlTrendlineType : xlLogarithmic /*各种变量的值和属性名的关系:http://mugiseyebrows.ru/excel/Excel.Range.html#Cells*/ trendLine->setProperty("Type", -4132); trendLine->setProperty("Name", "TrendLineName"); trendLine->setProperty("DisplayEquation", true);/*显示公式,显示R2*/ trendLine->setProperty("DisplayRSquared",true); /*获取公式*/ QAxObject *dataLabel = trendLine->querySubObject("DataLabel"); QString strFormula = dataLabel->property("Formula").toString(); getFormulaCoeffcient_kx_plus_b(strFormula, out_k, out_b); out_formular = strFormula.toStdString(); } /*将公式中的值自动填入,但是不能随着图表选择的数据范围动态刷新*/ QAxObject *kvalue_Cell = _curWorkSheet->querySubObject("Cells(int,int)", 1, 7); QString formular; formular.sprintf("=INDEX(LINEST(R1C3:R20C3,R1C2:R20C2),1)");/*注意:Y值在左,X值在右,绝对位置*/ kvalue_Cell->setProperty("Formula", formular); QAxObject *bvalue_Cell = _curWorkSheet->querySubObject("Cells(int,int)", 2, 7); formular.sprintf("=INDEX(LINEST(R1C3:R20C3,R1C2:R20C2),2)");/*注意:Y值在左,X值在右,绝对位置*/ bvalue_Cell->setProperty("Formula", formular); /* ./ 会将文件保存在我的文档目录下面*/ QString filepath = "./test.xlsx"; /*文件名字转换,否则Excel一直卡住,QDir::toNativeSeparators*/ workbooks->dynamicCall("SaveCopyAs(QString)", QDir::toNativeSeparators(filepath)); /*在关闭Excel之前先调用这个不显示警告框,否则会弹出是否保存sheet1的对话框*/ _excelObject->setProperty("DisplayAlerts", false); _excelObject->dynamicCall("Quit()"); delete _excelObject; _excelObject = NULL; OleUninitialize(); return 0; }
CMakeLists
cmake_minimum_required (VERSION 2.6 FATAL_ERROR)
project(QAxObject_Excel)
find_package (Qt5 REQUIRED Core Widgets AxContainer)
ADD_DEFINITIONS (${QT_DEFINITIONS})
ADD_DEFINITIONS(-D _XKEYCHECK_H)
ADD_EXECUTABLE (Demo main.cpp)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Demo)
TARGET_LINK_LIBRARIES (Demo Qt5::Core Qt5::Widgets Qt5::AxContainer)
简介的例子: Qt中使用QAxObject操作Excel
单元格详细操作: Qt之操作Excel
Excel vba文档:Excel VBA 参考
Excel 保存出错:Qt 使用QAxObject保存excel出错,使用双反斜线\路径分隔符
Excel COM 变量:The COM object is a QAxObject with the CLSID
Excel 自动拟合曲线:excel 自动获得拟合系数,自动引用,计算
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。