转自:https://blog.csdn.net/cannon_qi/article/details/79972258
QAxObject对COM对象进行了封装,QAxObject派生自QAxBase,而后者提供了一组API通过IUnknown(不清楚IUnknown的同学可以去看看COM对象模型)指针直接访问COM对象,我们这里讲的excel也是一个COM对象,因此我们可以通过QAxObject来操作它,为了便于理解,我们首先了解一下excel的对象的主要层次结构:
上图是excel对象的层次结构,1个excel就有1个Application对象,1个Application对象由多个Workbook对象组成,这些Workbook对象由Workbooks对象统一管理,Workbook对象下可以包含若干个Worksheet,这些Worksheet对象也有一个WorkSheets对象来统一管理,接下来是Range对象,这个对象就对应Worksheet里的表格单元了。
Application:Excel运行环境,也就是excel程序
WorkBook:表示实质意义上的一个excel工作簿文件,可以对其进行保存操作等等
WorkSheet:包含于Workbook,是一个Excel工作表 sheet1,sheet2等等
Range:包含于Worksheet,是excel表中一个或者多个单元格 例如(A1:C3)
单元格表示Cell[行,列];
使用excel COM组件流程:
---创建excel进程,设置进程界面不可见 Visible
---建立或者打开workbook对象(实际意义的excel文件)
---由workbook获取sheet对象
---设置操作区域range,并访问赋值等
---保存操作,不显示对话框 DisplayAlerts
---对于要处理多个excel文件需要关闭workbook
---关闭excel进程
好了大家应该清楚了Excel的对象的主要层次结构了吧,下面我们来看看QAxObject是怎么来导出excel的: (该部分理论参考别处网络文档,文章结尾表明参考处)
1、要在QT中使用QAxObject,需要在.pro文件中添加语句:CONFIG += qaxcontainer,之后便可以添加头文件:#include <QAxObject>
2、这里通过帮助类实现数据导出excel:(通过封装类,方便之后的使用)
// .pro 或则 .pri文件
需要在工程文件中添加组件 QT += axcontainer
//.h 文件:
#ifndef EXCELHELPER_H
#define EXCELHELPER_H
#include <QAxObject>
class ExcelHelper : public QObject
{
Q_OBJECT
public:
explicit ExcelHelper(QObject *parent = 0);
~ExcelHelper();
QString NewExcel(const QString &filename);
void FreeExcel();
void SaveExcel(const QString &fileName);
void SetCellValue(int row, int column, const QVariant &vale);
void SetCellPic(int row, int col, const QString &picAbsolutelyPath);
private:
bool CheckObjIsNull(QAxObject *obj);
private:
QAxObject* m_pExcelApp = Q_NULLPTR;
QAxObject* m_pWorkBooks = Q_NULLPTR;
QAxObject* m_pWorkBook = Q_NULLPTR;
QAxObject* m_pSheets = Q_NULLPTR;
QAxObject* m_pSheet = Q_NULLPTR;
};
#endif // EXCELHELPER_H
//.cpp文件
#include <QDir>
#include <QFile>
ExcelHelper::ExcelHelper(QObject *parent):QObject(parent)
{
}
ExcelHelper::~ExcelHelper()
{
FreeExcel();
}
bool ExcelHelper::CheckObjIsNull(QAxObject *obj)
{
return obj==Q_NULLPTR || obj->isNull();
}
QString ExcelHelper::NewExcel(const QString &filename)
{
QString errStr;
do
{
m_pExcelApp = new QAxObject("Excel.Application");
if(m_pExcelApp->isNull())
{
FreeExcel();
errStr = "没有找到EXCEL应用程序";
break;
}
m_pExcelApp->dynamicCall("SetVisible(bool)",false);
m_pExcelApp->setProperty("DisplayAlerts",false);
m_pWorkBooks = m_pExcelApp->querySubObject("Workbooks"); // 一个excel应用程序可以有多个打开的workbook,统一由workbooks管理
if(CheckObjIsNull(m_pWorkBooks))
{
errStr = "取得Excel的Workbooks失败";
break;
}
QFile file(filename);
if(file.exists())
{
m_pWorkBook = m_pWorkBooks->querySubObject("Open(const QString &)",filename); // 打开一个workbook
}
else
{
m_pWorkBooks->dynamicCall("Add");
m_pWorkBook = m_pExcelApp->querySubObject("ActiveWorkBook");
}
if(CheckObjIsNull(m_pWorkBook))
{
errStr = "打开Excel的Workbook失败";
break;
}
m_pSheets = m_pWorkBook->querySubObject("Sheets");
if(CheckObjIsNull(m_pSheets))
{
errStr = "打开Excel的Sheets失败";
break;
}
m_pSheet = m_pSheets->querySubObject("Item(int)",1);
if(CheckObjIsNull(m_pSheet))
{
errStr = "打开Excel的Sheet失败";
break;
}
}
while(0);
return errStr;
}
void ExcelHelper::SetCellValue(int row, int column, const QVariant &value)
{
// querySubObject返回的对象为本对象的子对象,当本对象销毁时会自动删除子对象
QAxObject *pRange = m_pSheet->querySubObject("Cells(int,int)", row, column); // 取得QAxObject对象指针
if(CheckObjIsNull(pRange))
{
return;
}
pRange->dynamicCall("Value", value);
//内容居中
pRange->setProperty("HorizontalAlignment", -4108);
pRange->setProperty("VerticalAlignment", -4108);
// pRange->setProperty("RowHeight", 50); //设置单元格行高
// pRange->setProperty("ColumnWidth", 30); //设置单元格列宽
// pRange->setProperty("HorizontalAlignment", -4108); //左对齐(xlLeft):-4131 居中(xlCenter):-4108 右对齐(xlRight):-4152
// pRange->setProperty("VerticalAlignment", -4108); //上对齐(xlTop)-4160 居中(xlCenter):-4108 下对齐(xlBottom):-4107
// pRange->setProperty("WrapText", true); //内容过多,自动换行
// pRange->dynamicCall("ClearContents()"); //清空单元格内容
// QAxObject* interior =pRange->querySubObject("Interior");
// interior->setProperty("Color", QColor(0, 255, 0)); //设置单元格背景色(绿色)
// QAxObject* border = cell->querySubObject("Borders");
// border->setProperty("Color", QColor(0, 0, 255)); //设置单元格边框色(蓝色)
// QAxObject *font = cell->querySubObject("Font"); //获取单元格字体
// font->setProperty("Name", QStringLiteral("华文彩云")); //设置单元格字体
// font->setProperty("Bold", true); //设置单元格字体加粗
// font->setProperty("Size", 20); //设置单元格字体大小
// font->setProperty("Italic", true); //设置单元格字体斜体
// font->setProperty("Underline", 2); //设置单元格下划线
// font->setProperty("Color", QColor(255, 0, 0)); //设置单元格字体颜色(红色)
if(row == 1){
//加粗
QAxObject *font = pRange->querySubObject("Font"); //获取单元格字体
font->setProperty("Bold",true); //设置单元格字体加粗
}
}
// 向excel中插入图片
void ExcelHelper::SetCellPic(int row, int column, const QString &picAbsolutelyPath)
{
QAxObject *pShape = m_pSheet->querySubObject("Shapes");
if(CheckObjIsNull(pShape))
{
return;
}
QAxObject *pRange = m_pSheet->querySubObject("Cells(int,int)", row, column);
if(CheckObjIsNull(pRange))
{
return;
}
double left = pRange->property("Left").toDouble(); // 取得该cell的左上角坐标
double top = pRange->property("Top").toDouble();
QPixmap pix(picAbsolutelyPath);
QSize size = pix.size(); // 取得图片的长宽
QString picPath = QDir::toNativeSeparators(picAbsolutelyPath);
pShape->dynamicCall("AddPicture( QString&, bool, bool, double, double, double, double",
picPath,true,true,left,top,size.width()*0.8,size.height()*0.8); /*AddPicture参数 left,top是图片所在表格项的左上角,最后2个参数是图片宽高 */
}
void ExcelHelper::SaveExcel(const QString &fileName)
{
QAxObject *pRange = m_pSheet->querySubObject("UsedRange");
if(!CheckObjIsNull(pRange))
{
QAxObject *pCell = pRange->querySubObject("Columns");
if(CheckObjIsNull(pCell))
{
pCell->dynamicCall("AutoFit");
}
pRange->setProperty("HorizontalAlignment",-4108);
pRange->setProperty("VerticalAlignment",-4108);
}
m_pWorkBook->dynamicCall("SaveAs(const QString &)",QDir::toNativeSeparators(fileName));
}
void ExcelHelper::FreeExcel()
{
if(m_pExcelApp != Q_NULLPTR)
{
m_pExcelApp->dynamicCall("Quit()");
delete m_pExcelApp;
m_pExcelApp = Q_NULLPTR;
}
}
//增加1个Worksheet,这里要注意:默认有一个sheet,需要的时候再调用这个函数
void ExcelHelper::appendSheet(const QString &sheetName)
{
int cnt = 1;
QAxObject *pLastSheet = m_pSheets->querySubObject("Item(int)", cnt);
m_pSheets->querySubObject("Add(QVariant)", pLastSheet->asVariant());
m_pSheet = m_pSheets->querySubObject("Item(int)", cnt);
pLastSheet->dynamicCall("Move(QVariant)", m_pSheet->asVariant());
m_pSheet->setProperty("Name", sheetName);
}
主要参考:https://blog.csdn.net/luols/article/details/48781075
https://blog.csdn.net/w_ww_w/article/details/9167573
调用举例:
// fileName为需要保存的文件名,titles为excel表头列名,dataVec为n行m列的数据
bool ExportDataToExcel(const QString &fileName, const QStringList &titleLs, const QVector<QStringList> &dataVec)
{
if(!newExcel(fileName))
return false;
/*
//进度条显示
QProgressDialog m_progressDlg;
m_progressDlg.reset();
m_progressDlg.setLabelText(QString::fromLocal8Bit("正在导出数据到excel,数据总条数[%1],请稍候...").arg(dataVec.size()));
m_progressDlg.setCancelButtonText(QString::fromLocal8Bit("取消导出"));
m_progressDlg.setWindowFlags(m_progressDlg.windowFlags() &~ Qt::WindowContextHelpButtonHint);
m_progressDlg.setRange(0,table.size());
m_progressDlg.raise();*/
for(int i = 0; i < titleLs.size();++i)
{
setCellValue(1,i+1,titleLs.at(i));
}
int row = 2;
for(const QStringList &datals: dataVec)
{
int col = 1;
for(const QString &data : datals)
{
setCellValue(row,col++,data);
}
row++;
/*qApp->processEvents(); // 必须添加此句,进度条才会有进度显示,否则进度条将不会动
m_progressDlg.setValue(row);
if(m_progressDlg.wasCanceled())
{
break;
}*/
m_progressDlg.setValue(row);
}
saveExcel(fileName);
freeExcel();
return true;
}
// 此处为外部调用函数
bool Export()
{
QString filepath = QFileDialog::getSaveFileName(this,tr("保存信息"),".",tr("Microsoft Office Excel (*.xlsx)"));
if(filepath.isEmpty())
return;
QStringList titlels;
titlels << "序列号"<<"子网号";
QVector<QStringList> vec;
for(int i =0; i<100; i++)
{
vec.push_back(QStringList()<<i<<i+1);
}
ExcelHelper excel;
excel.ExportDataToExcel(filepath,titlels,vec);
}