Qt自带的QAxObject可以通过COM组件的方式操控微软的Offfice组件,包括Word、Excel、PowerPoint。
使用Qt读写Excel数据的场景较多。
前提:
1. Qt项目中的Pro文件中必须加上下面一行,才能使用 QAxObject 库。
qt += axcontainer
2. 运行后面的代码可能需要包含以下头文件,按需添加。
#include <QAxObject>
#include <QAxWidget>
#include <QtDebug>
0. 关键代码
批量读取:
QAxObject *range = worksheet->querySubObject("Range(QString)", "B13:C1000");
批量写:
//QList<QVariant> mLstData; 自己组装好的数据
//QString strMergeCell 是自己组装好的字符串,如 E1:E1000
AxObject *merge_range = worksheet->querySubObject("Range(const QString&)", strMergeCell);
merge_range->setProperty("Value", QVariant(mLstData));
1. 文件打开和关闭及基本单元格读写
(这种调用方式感觉像是在模拟执行Excel软件的菜单栏命令,微软的COM组件也是挺奇葩的,满满的VB味道)
// QString filepath 是文件路径
//后台启动Excel组件
QAxObject *myexcel = new QAxObject("Excel.Application");
myexcel->dynamicCall("SetVisible(bool)", false);
myexcel->setProperty("Visible", false);
//打开文件
QAxObject *workbooks = myexcel->querySubObject("WorkBooks");
workbooks ->dynamicCall("Open(const QString&", filePath);
//打开第一个工作表
QAxObject *workbook = myexcel->querySubObject("ActiveWorkBook"); //工作簿
QAxObject *worksheet = workbook ->querySubObject("Sheets(int)",1);
//读取A6格的数据
QAxObject *cell = worksheet ->querySubObject("Range(QVariant,QVariant)", "A6");
QString centerkm = cell->dynamicCall("Value2()").toString();
//往A6格写入数据 yourData
cell ->setProperty("Value", QVariant(yourData));
//保存文件,strFileName是保存文件路径
workbook ->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(strFileName));
//关闭工作簿
workbook ->dynamicCall("Close()");
//释放所有工作表
worksheet ->clear();
//退出Excel
myexcel ->dynamicCall("Quit()");
//释放excel指针
delete myexcel ;
2. 批量读写
2.1 读取单列或者单行
下面两种写法效果相同。
QString col= "B4:B5";
// 可以自己拼接,如
// QString col = "B4:B";
// col.append(QString::number(99));
// col 就是 B4:B99
QAxObject *myColAx= worksheet->querySubObject("Range(QString)", col);
QVariant colData = cell->dynamicCall("Value2()");
QVariantList colDataList = colData.toList(); //先转成List
//qDebug()<<colDataList.count();
//遍历List
for(int i=0; i<= colDataList.count() - 1; i++)
{
QVariantList rowData = colDataList[i].toList() ;
qDebug()<< rowData[0].toString();
}
2.2 批量读取多列多行
QString Range = "B1:C12"; //12行2列
QAxObject *rangeAx = sheet->querySubObject("Range(QString)", Range);
QVariant rangeData = rangeAx ->dynamicCall("Value2()");
QVariantList rangeDataList = rangeData.toList(); //先转成List
//qDebug() << rangeDataList.count();
//遍历List
for(int i=0; i<= rangeDataList.count() - 1; i++)
{
QVariantList rowData = rangeDataList[i].toList() ;
qDebug()<< rowData[0].toString(); //打印第i行第0列,即列B
qDebug()<< rowData[1].toString(); //打印第i行第1列,即列C
}
注意:B1:C12这种范围读取的写法返回的结果是个嵌套List的List。QList<QList<>>这种。
直接打印 colData 返回如下。其中11,12是 B4 B5单元格的值。
QVariant(QVariantList, (QVariant(QVariantList, (QVariant(QString, "11"))), QVariant(QVariantList, (QVariant(QString, "12")))))
2.3 批量写和批量读类似
批量写未测试,仅供参考。
QList<QVariant> data;
QList<QString> strList;
strList << "sdfsd" << "asdfjoasdf";
data << strList;
QAxObject *rangeAx = worksheet->querySubObject("Range(const QString&)", "B1:C12");
rangeAx ->setProperty("Value", QVariant(data));
3. 读取整个Excel
QAxObject *usedRange = worksheet->querySubObject("UsedRange");
QVariant cell = usedRange->dynamicCall("Value");
4. 自动判断读取行数
很多时候,需要代码自己判断指定的数据区域,比如从第一行开始读取,直到最后一行。如何判断最后一行呢?
//获取该sheet的使用范围对象
QAxObject * usedrange = worksheet->querySubObject("UsedRange");
QAxObject * rows = usedrange->querySubObject("Rows");
QAxObject * columns = usedrange->querySubObject("Columns");
int intRows = rows->property("Count").toInt();
int intCols = columns->property("Count").toInt();
qDebug() << "xls行数:"<<intRows;
qDebug() << "xls列数:"<<intCols;
博主注:如果是解析机器生成的Excel文件,那么此方法适用。如果是人手工制作的Excel文件,可能存在有些行列无内容但是也被设置或使用后,被代码判定为有效行。如果你的代码需要十分严谨,建议自己编写判断行列是否有效的代码。