Qt之操作Excel
2015-11-25 09:43
218 查看
本文主要参考博客:Qt之操作Excel和EXCEL_VBA完全手册,为公司项目设计了一个”Report to
Excel“的功能。本文浅谈了几点我对Qt操作Excel编程的一些体会。
一、什么是VBA
Visual Basic
Application是一种自动化语言(过去称为“宏语言”),可以用它是常用的过程或进程自动化,可以创建自定义的解决方案。目前,主要用它来扩展Window
office的功能。
要了解VBA,有两个简单的办法:
1,查看“EXCEL帮助(F1)" -> ”搜索“ -> ”开发人员参考“
-> ”VB语言“
2,查看宏录制
这类的”宏“指一系列EXCEL能够执行的名字保存的命令。
参考EXCEL_VBA完全手册的第一节。或通过右击worksheet,查看源码的方式进入。同过宏录制,查看源代码,获知VBA的一些属性值和操作方法,如左对齐(xlLeft):-4131
;居中(xlCenter):-4108
;右对齐(xlRight):-4152
;上对齐(xlTop):-4160 ;居中(xlCenter):4108 ;下对齐(xlBottom):-4107等等。
二、Qt是如何来操作Excel?
Qt操作Excel主要通过QAxObject + Excel
VBA来实现。查看Qt的帮助文档:
The QAxObject class provides a
QObject that wraps a COM object.
A QAxObject can be instantiated as an
empty object, with the name of the COM object it should wrap, or
with a pointer to the IUnknown that represents an existing COM
object. If the COM object implements the IDispatch interface, the
properties, methods and events of that object become available as
Qt properties, slots and signals. The base class, QAxBase, provides
an API to access the COM object directly through the IUnknown
pointer.
QAxObject is a QObject and can be
used as such, e.g. it can be organized in an object hierarchy,
receive events and connect to signals and slots.
QAxObject also inherits most of its
ActiveX-related functionality from QAxBase, notably dynamicCall()
and querySubObject().
这段的大意就是:QAxObject是对COM对象的封装。COM
Object的属性、方法和事件与Qt的属性、slot方法和信号对应。其中,最重要的两个函数是:dynamicCall() 和 querySubObject()。
此外,可以查看“QAxbase”,它提供了COM type和Qt
property的对照表,并提供了dynamicCall() 和
querySubObject()函数以及 QObject::property() and
QObject::setProperty()函数(Note that it is faster to get and set
properties using QObject::property() and
QObject::setProperty())的说明。
函数querySubObject()实现对象关联或对象转换(从COM Object转为Qt
Object),如:QAxObject *
workBooks = excel.querySubObject("WorkBooks");
函数dynamicCall() 实现跨QT到COM的函数调用,如:workBooks->dynamicCall("Open(const
QString&)",
QString("D:/Development/Trunk09/test.xlsx"));
函数property() 获取属性,函数setProperty()设置属性。
三、示例代码
1,读Excel文件
新建一个“Qt
console”应用程序,在“.pro文件”中添加(查看QAxObject即可知),QT +=
axcontainer,然后在main文件中添加如下代码:
#include
#include
#include
#include
// 使用 CoInitializeEx(NULL,
COINIT_MULTITHREADED);
int main(int argc, char
*argv[])
{
// QCoreApplication a(argc, argv);
// 在后台线程中使用QAxObject必须先初始化
CoInitializeEx(NULL, COINIT_MULTITHREADED);
QAxObject excel("Excel.Application");
excel.setProperty("Visible", true);
// 调试的时候设为true,release模式设为false,不可见
QAxObject * workBooks = excel.querySubObject("WorkBooks");
workBooks->dynamicCall("Open(const QString&)",
QString("D:/Development/Trunk09/test.xlsx"));
QVariant titleValue = excel.property("Caption");
// 获取标题
qDebug() << "excel title : " << titleValue;
QAxObject * workBook =
excel.querySubObject("ActiveWorkBook");
QAxObject * workSheets = workBook->querySubObject("Sheets");
// Sheets也可换作WorkSheets
int sheetCount = workSheets->property("Count").toInt();
// 获取工作表数目
qDebug() << "sheet count : " << sheetCount;
for (int i = 1; i <= sheetCount; i++)
{
QAxObject *workSheet =
workBook->querySubObject("Sheets(int)", i);
// 可以用WorkSheets(int)
QString sheetName =
workSheet->property("Name").toString();
// 获取工作表名称
qDebug() << "sheet"
<< QString::number(i, 10) << " name: " <<
sheetName;
}
if (sheetCount > 0)
{
QAxObject *workSheet =
workBook->querySubObject("Sheets(int)", 1);
QAxObject *usedRange =
workSheet->querySubObject("UsedRange");
QAxObject *rows =
usedRange->querySubObject("Rows");
QAxObject *columns =
usedRange->querySubObject("Columns");
int startingRow =
usedRange->property("Row").toInt();
int startingColumn =
usedRange->property("Column").toInt();
int rowCount =
rows->property("Count").toInt();
int columnCount =
columns->property("Count").toInt();
for (int i = startingRow; i
<= rowCount; i++)
{
for(int j = startingColumn; j <= columnCount;
j++)
{
QAxObject
* cell = workSheet->querySubObject("Cells(int, int)", i,
j);
QVariant
cellValue = cell->property("Value");
qDebug()
<< "row-" << QString::number(i,10) << "-column-"
<< QString::number(j,10) << ": " <<
cellValue;
}
}
}
workBook->dynamicCall("Close(Boolen)", false);
// 关闭文件
excel.dynamicCall("Quit(void)");
// 退出
//return a.exec();
}
注:QT中的文件路径,既可以用两个反斜杠,其中一个是转义字符,也可以用一个斜杠。
2,写Excel文件
新建一个“Qt
console”应用程序,在“.pro文件”中添加(查看QAxObject即可知),QT +=
axcontainer,然后在main文件中添加如下代码:
#include
#include
#include
#include
#include
int main(int argc, char
*argv[])
{
//QCoreApplication a(argc, argv);
// 在后台线程中使用QAxObject必须先初始化
CoInitializeEx(NULL,
COINIT_MULTITHREADED);
QAxObject excel("Excel.Application");
excel.setProperty("Visible", true);
QAxObject * workBooks =
excel.querySubObject("WorkBooks");
workBooks->dynamicCall("Open(const
QString&)",
QString("D:\\Development\\Trunk09\\testw.xlsx"));
QVariant titleValue = excel.property("Caption");
// 获取标题
qDebug() << "excel title : " <<
titleValue;
QAxObject * workBook =
excel.querySubObject("ActiveWorkBook");
QAxObject * workSheets =
workBook->querySubObject("Sheets");
// Sheets也可换作WorkSheets
// 删除工作表(删除第一个)
QAxObject * firstSheet =
workSheets->querySubObject("Item(int)", 1);
firstSheet->dynamicCall("delete");
// 插入工作表(插入到最后一行)
int sheetCount =
workSheets->property("Count").toInt();
// 获取工作表数目
QAxObject * lastSheet =
workSheets->querySubObject("Item(int)", sheetCount);
QAxObject * workSheet =
workSheets->querySubObject("Add(QVariant",
lastSheet->asVariant());
lastSheet->dynamicCall("Move(QVariant)",
workSheet->asVariant());
// 设置工作表名称
workSheet->setProperty("Name", "Qt
Sheet");
// 操作单元格(第二行第二列)
QAxObject * cell =
workSheet->querySubObject("Cells(int, int)", 2, 2);
cell->setProperty("Value", "Java C++ C# PHP
Perl Python Delphi Ruby"); //
设单元格的值
cell->setProperty("RowHight", 50);
cell->setProperty("ColumnWidth", 30);
cell->setProperty("HoriontalAligment",
-4108); // 左对齐(xlLeft):-4131
;居中(xlCenter):-4108 ;右对齐(xlRight):-4152
cell->setProperty("VerticalAligment", -4108);
// 上对齐(xlTop):-4160
;居中(xlCenter):4108 ;下对齐(xlBottom):-4107
cell->setProperty("WrapText", true);
// 内容过多,自动换行
//cell->dynamicCall("ClearContents()");
// 清空单元格内容
QAxObject* interior =
cell->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)); //设置单元格字体颜色(红色)
//设置单元格内容,并合并单元格(第5行第3列-第8行第5列)
QAxObject *cell_5_6 =
workSheet->querySubObject("Cells(int,int)", 5, 3);
cell_5_6->setProperty("Value", "Java");
//设置单元格值
QAxObject *cell_8_5 =
workSheet->querySubObject("Cells(int,int)", 8, 5);
cell_8_5->setProperty("Value", "C++");
QString merge_cell;
merge_cell.append(QChar(3 - 1 + 'A'));
//初始列
merge_cell.append(QString::number(5));
//初始行
merge_cell.append(":");
merge_cell.append(QChar(5 - 1 + 'A'));
//终止列
merge_cell.append(QString::number(8));
//终止行
QAxObject *merge_range =
workSheet->querySubObject("Range(const QString&)",
merge_cell);
merge_range->setProperty("HorizontalAlignment", -4108);
merge_range->setProperty("VerticalAlignment",
-4108);
merge_range->setProperty("WrapText",
true);
merge_range->setProperty("MergeCells", true);
//合并单元格
//merge_range->setProperty("MergeCells",
false); //拆分单元格
//work_book->dynamicCall("Save()");
//保存文件(为了对比test与下面的test2文件,这里不做保存操作)
work_book->dynamicCall("SaveAs(const QString&)",
"E:\\test2.xlsx"); //另存为另一个文件
workBook->dynamicCall("Close(Boolean)",
false); //关闭文件
excel.dynamicCall("Quit(void)");
//退出
//return a.exec();
}
四、项目实践
将主界面的数据保存到excel,由于保存时间比较长,所以开线程执行该操作。
void SaveReportThread::run()
{
//
在后台线程中使用QAxObject必须先初始化
CoInitializeEx(NULL,
COINIT_MULTITHREADED);
//SaveToExcel();
SaveToWord();
emit
SIGNAL_SaveReportFinish();
}
void SaveReportThread::SaveToExcel()
{
QAxObject* pExcelApp =
new QAxObject("Excel.Application"); //
创建EXCEL对象,启动Excel.exe进程
pExcelApp->setProperty("DisplayAlerts", false);
//
保存时不提示覆盖
//pExcelApp->setProperty("Visible", true);
// 操作时可以看见EXCEL窗口,调试用
// 打开测试报告模板
QAxObject* pWorkBooks =
pExcelApp->querySubObject("WorkBooks");
pWorkBooks->dynamicCall("Open(const QString&)",
QCoreApplication::applicationDirPath() +
"/TestReportTemplate.xlsx");
QAxObject* pWorkBook =
pExcelApp->querySubObject("ActiveWorkBook");
//
如果要保存全部测试报告,先在模板文件中复制多份sheet模板
QAxObject* pWorkSheet =
pWorkBook->querySubObject("WorkSheets(int)", 1);
if (m_bSaveAll)
{
for (int i = 1; i <
m_pMainwindow->m_vecItemList.size(); i++)
pWorkSheet->dynamicCall("Copy(const QVariant&)",
pWorkSheet->asVariant());
}
//
for循环流程兼容保存单个和全部报告
for (int i = 0; i <
m_pMainwindow->m_vecItemList.size(); i++)
{
if (m_bSaveAll)
emit
SIGNAL_ItemSelected(i); // 通知UI切换测试项,同步操作
// 1.修改sheet名称
pWorkSheet =
pWorkBook->querySubObject("WorkSheets(int)", i + 1);
pWorkSheet->dynamicCall("Select()");
// 必须先select当前sheet
pWorkSheet->setProperty("Name",
m_pMainwindow->m_strCurrentItemName);
// 2.填写测试基本信息
int iRow = 2;
pWorkSheet->querySubObject("Cells(int,int)",
iRow++, 2)->setProperty("Value",
QDate::currentDate().toString("yyyy-MM-dd"));
pWorkSheet->querySubObject("Cells(int,int)",
iRow++, 2)->setProperty("Value",
QTime::currentTime().toString());
pWorkSheet->querySubObject("Cells(int,int)",
iRow++, 2)->setProperty("Value", "user");
foreach (QString strInfo, m_listBaseInfo)
pWorkSheet->querySubObject("Cells(int,int)", iRow++,
3)->setProperty("Value", strInfo);
// 3.填写测试项名称和最终结果
iRow = 18;
pWorkSheet->querySubObject("Cells(int,int)",
iRow, 1)->setProperty("Value",
m_pMainwindow->m_strCurrentItemName);
pWorkSheet->querySubObject("Cells(int,int)",
iRow, 2)->setProperty("Value",
m_pMainwindow->m_vecItemList[m_pMainwindow->m_iCurrentItemIndex]->GetTestPassOrFail());
// 4.填写静态参数
iRow = 21;
int iCount =
m_pMainwindow->ui->listStaticParams->count();
// 有需要手工输入的静态参数也写进测试报告中
QVector vecUserParams;
if
(m_pMainwindow->ui->doubleSpinBoxPower->isVisible())
{
QStringList listPower;
listPower.append(C_PARA_Power);
listPower.append(m_pMainwindow->ui->doubleSpinBoxPower->text());
vecUserParams.push_back(listPower);
iCount++;
}
if
(m_pMainwindow->ui->doubleSpinBoxFrequency->isVisible())
{
QStringList listFreq;
listFreq.append(C_PARA_Freq);
listFreq.append(m_pMainwindow->ui->doubleSpinBoxFrequency->text());
vecUserParams.push_back(listFreq);
iCount++;
}
for (int i = 0; i < iCount; i++)
{
QStringList listParam;
if (i <
m_pMainwindow->ui->listStaticParams->count())
listParam =
m_pMainwindow->ui->listStaticParams->item(i)->text().split("=");
// 静态参数框控件中的内容
else
listParam = vecUserParams[i -
m_pMainwindow->ui->listStaticParams->count()];
// 手工输入的参数
if (i >
0)
{
//
除了第一行,每次都要复制前一行再插入一行,因为报告模板中有第一行的模板
QAxObject* pRow =
pWorkSheet->querySubObject("Rows(int)", iRow);
pRow->dynamicCall("Select()");
pRow->dynamicCall("Copy()");
pRow =
pWorkSheet->querySubObject("Rows(int)", ++iRow);
pRow->dynamicCall("Select()");
pRow->dynamicCall("Insert()");
}
pWorkSheet->querySubObject("Cells(int,int)", iRow,
1)->setProperty("Value", listParam[0]);
pWorkSheet->querySubObject("Cells(int,int)", iRow,
2)->setProperty("Value", listParam[1]);
}
// 5.填写结果列表
iRow += 3;
for (int i = 0; i <
m_pMainwindow->ui->tableResult->rowCount(); i++)
{
if (i >
0)
{
//
除了第一行,每次都要复制前一行再插入一行,因为报告模板中有第一行的模板
QAxObject* pRow =
pWorkSheet->querySubObject("Rows(int)", iRow);
pRow->dynamicCall("Select()");
pRow->dynamicCall("Copy()");
pRow =
pWorkSheet->querySubObject("Rows(int)", ++iRow);
pRow->dynamicCall("Select()");
pRow->dynamicCall("Insert()");
}
if
(m_pMainwindow->ui->tableResult->item(i, 0) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
1)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
0)->text());
if
(m_pMainwindow->ui->tableResult->item(i, 1) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
2)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
1)->text());
if
(m_pMainwindow->ui->tableResult->item(i, 2) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
3)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
2)->text());
if
(m_pMainwindow->ui->tableResult->item(i, 3) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
4)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
3)->text());
if
(m_pMainwindow->ui->tableResult->item(i, 4) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
5)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
4)->text());
if
(m_pMainwindow->ui->tableResult->item(i, 5) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
6)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
5)->text());
}
// 6.插入成功率图
iRow += 2;
QString strImagePath =
QDir::toNativeSeparators(QCoreApplication::applicationDirPath() +
"/pic.png"); // 必须把路径中的'/'转换成'\\'
emit SIGNAL_ExportPicture(strImagePath);
// 通知UI线程保存成功率图片,同步操作
if (QFile::exists(strImagePath))
{
QImage
image(strImagePath);
double
dRowHeight = pWorkSheet->querySubObject("Cells(int,int)", iRow,
1)->property("Height").toDouble(); //
每一行的高度,单位磅
double
width = image.width() * 0.75;
// 图片相对于左上角偏移的宽度,单位磅
double
height = image.height() * 0.75;
// 图片相对于左上角偏移的高度,单位磅
QAxObject*
pShapes = pWorkSheet->querySubObject("Shapes");
pShapes->dynamicCall("AddPicture(QString&,bool,bool,double,double,double,double)",
strImagePath, false, true, 0, iRow * dRowHeight, width,
height);
QFile::remove(strImagePath);
}
// 调整列宽
QAxObject* pAllCells =
pWorkSheet->querySubObject("Cells()");
pAllCells->dynamicCall("Select()");
pAllCells->querySubObject("EntireColumn()")->dynamicCall("AutoFit()");
pWorkSheet->querySubObject("Cells(int,int)",
1, 1)->dynamicCall("Select()");
// 默认选中第一个单元格
if (!m_bSaveAll)
break;
}
// 默认选中第一个sheet
pWorkSheet =
pWorkBook->querySubObject("WorkSheets(int)", 1);
pWorkSheet->dynamicCall("Select()");
// 另存为测试报告文件
QString ReportPath =
QDir::toNativeSeparators(QCoreApplication::applicationDirPath());
// 必须把路径中的'/'转换成'\\'
if (m_bSaveAll)
ReportPath += "\\TestReport_All.xlsx";
else
ReportPath += "\\TestReport_" +
m_pMainwindow->m_strCurrentItemName + ".xlsx";
pWorkBook->dynamicCall("SaveAs(const QString&)",
ReportPath);
pWorkBook->dynamicCall("Close()");
pWorkBooks->dynamicCall("Close()");
delete pExcelApp;
pExcelApp = NULL;
}
Excel“的功能。本文浅谈了几点我对Qt操作Excel编程的一些体会。
一、什么是VBA
Visual Basic
Application是一种自动化语言(过去称为“宏语言”),可以用它是常用的过程或进程自动化,可以创建自定义的解决方案。目前,主要用它来扩展Window
office的功能。
要了解VBA,有两个简单的办法:
1,查看“EXCEL帮助(F1)" -> ”搜索“ -> ”开发人员参考“
-> ”VB语言“
2,查看宏录制
这类的”宏“指一系列EXCEL能够执行的名字保存的命令。
参考EXCEL_VBA完全手册的第一节。或通过右击worksheet,查看源码的方式进入。同过宏录制,查看源代码,获知VBA的一些属性值和操作方法,如左对齐(xlLeft):-4131
;居中(xlCenter):-4108
;右对齐(xlRight):-4152
;上对齐(xlTop):-4160 ;居中(xlCenter):4108 ;下对齐(xlBottom):-4107等等。
二、Qt是如何来操作Excel?
Qt操作Excel主要通过QAxObject + Excel
VBA来实现。查看Qt的帮助文档:
The QAxObject class provides a
QObject that wraps a COM object.
A QAxObject can be instantiated as an
empty object, with the name of the COM object it should wrap, or
with a pointer to the IUnknown that represents an existing COM
object. If the COM object implements the IDispatch interface, the
properties, methods and events of that object become available as
Qt properties, slots and signals. The base class, QAxBase, provides
an API to access the COM object directly through the IUnknown
pointer.
QAxObject is a QObject and can be
used as such, e.g. it can be organized in an object hierarchy,
receive events and connect to signals and slots.
QAxObject also inherits most of its
ActiveX-related functionality from QAxBase, notably dynamicCall()
and querySubObject().
这段的大意就是:QAxObject是对COM对象的封装。COM
Object的属性、方法和事件与Qt的属性、slot方法和信号对应。其中,最重要的两个函数是:dynamicCall() 和 querySubObject()。
此外,可以查看“QAxbase”,它提供了COM type和Qt
property的对照表,并提供了dynamicCall() 和
querySubObject()函数以及 QObject::property() and
QObject::setProperty()函数(Note that it is faster to get and set
properties using QObject::property() and
QObject::setProperty())的说明。
函数querySubObject()实现对象关联或对象转换(从COM Object转为Qt
Object),如:QAxObject *
workBooks = excel.querySubObject("WorkBooks");
函数dynamicCall() 实现跨QT到COM的函数调用,如:workBooks->dynamicCall("Open(const
QString&)",
QString("D:/Development/Trunk09/test.xlsx"));
函数property() 获取属性,函数setProperty()设置属性。
三、示例代码
1,读Excel文件
新建一个“Qt
console”应用程序,在“.pro文件”中添加(查看QAxObject即可知),QT +=
axcontainer,然后在main文件中添加如下代码:
#include
#include
#include
#include
// 使用 CoInitializeEx(NULL,
COINIT_MULTITHREADED);
int main(int argc, char
*argv[])
{
// QCoreApplication a(argc, argv);
// 在后台线程中使用QAxObject必须先初始化
CoInitializeEx(NULL, COINIT_MULTITHREADED);
QAxObject excel("Excel.Application");
excel.setProperty("Visible", true);
// 调试的时候设为true,release模式设为false,不可见
QAxObject * workBooks = excel.querySubObject("WorkBooks");
workBooks->dynamicCall("Open(const QString&)",
QString("D:/Development/Trunk09/test.xlsx"));
QVariant titleValue = excel.property("Caption");
// 获取标题
qDebug() << "excel title : " << titleValue;
QAxObject * workBook =
excel.querySubObject("ActiveWorkBook");
QAxObject * workSheets = workBook->querySubObject("Sheets");
// Sheets也可换作WorkSheets
int sheetCount = workSheets->property("Count").toInt();
// 获取工作表数目
qDebug() << "sheet count : " << sheetCount;
for (int i = 1; i <= sheetCount; i++)
{
QAxObject *workSheet =
workBook->querySubObject("Sheets(int)", i);
// 可以用WorkSheets(int)
QString sheetName =
workSheet->property("Name").toString();
// 获取工作表名称
qDebug() << "sheet"
<< QString::number(i, 10) << " name: " <<
sheetName;
}
if (sheetCount > 0)
{
QAxObject *workSheet =
workBook->querySubObject("Sheets(int)", 1);
QAxObject *usedRange =
workSheet->querySubObject("UsedRange");
QAxObject *rows =
usedRange->querySubObject("Rows");
QAxObject *columns =
usedRange->querySubObject("Columns");
int startingRow =
usedRange->property("Row").toInt();
int startingColumn =
usedRange->property("Column").toInt();
int rowCount =
rows->property("Count").toInt();
int columnCount =
columns->property("Count").toInt();
for (int i = startingRow; i
<= rowCount; i++)
{
for(int j = startingColumn; j <= columnCount;
j++)
{
QAxObject
* cell = workSheet->querySubObject("Cells(int, int)", i,
j);
QVariant
cellValue = cell->property("Value");
qDebug()
<< "row-" << QString::number(i,10) << "-column-"
<< QString::number(j,10) << ": " <<
cellValue;
}
}
}
workBook->dynamicCall("Close(Boolen)", false);
// 关闭文件
excel.dynamicCall("Quit(void)");
// 退出
//return a.exec();
}
注:QT中的文件路径,既可以用两个反斜杠,其中一个是转义字符,也可以用一个斜杠。
2,写Excel文件
新建一个“Qt
console”应用程序,在“.pro文件”中添加(查看QAxObject即可知),QT +=
axcontainer,然后在main文件中添加如下代码:
#include
#include
#include
#include
#include
int main(int argc, char
*argv[])
{
//QCoreApplication a(argc, argv);
// 在后台线程中使用QAxObject必须先初始化
CoInitializeEx(NULL,
COINIT_MULTITHREADED);
QAxObject excel("Excel.Application");
excel.setProperty("Visible", true);
QAxObject * workBooks =
excel.querySubObject("WorkBooks");
workBooks->dynamicCall("Open(const
QString&)",
QString("D:\\Development\\Trunk09\\testw.xlsx"));
QVariant titleValue = excel.property("Caption");
// 获取标题
qDebug() << "excel title : " <<
titleValue;
QAxObject * workBook =
excel.querySubObject("ActiveWorkBook");
QAxObject * workSheets =
workBook->querySubObject("Sheets");
// Sheets也可换作WorkSheets
// 删除工作表(删除第一个)
QAxObject * firstSheet =
workSheets->querySubObject("Item(int)", 1);
firstSheet->dynamicCall("delete");
// 插入工作表(插入到最后一行)
int sheetCount =
workSheets->property("Count").toInt();
// 获取工作表数目
QAxObject * lastSheet =
workSheets->querySubObject("Item(int)", sheetCount);
QAxObject * workSheet =
workSheets->querySubObject("Add(QVariant",
lastSheet->asVariant());
lastSheet->dynamicCall("Move(QVariant)",
workSheet->asVariant());
// 设置工作表名称
workSheet->setProperty("Name", "Qt
Sheet");
// 操作单元格(第二行第二列)
QAxObject * cell =
workSheet->querySubObject("Cells(int, int)", 2, 2);
cell->setProperty("Value", "Java C++ C# PHP
Perl Python Delphi Ruby"); //
设单元格的值
cell->setProperty("RowHight", 50);
cell->setProperty("ColumnWidth", 30);
cell->setProperty("HoriontalAligment",
-4108); // 左对齐(xlLeft):-4131
;居中(xlCenter):-4108 ;右对齐(xlRight):-4152
cell->setProperty("VerticalAligment", -4108);
// 上对齐(xlTop):-4160
;居中(xlCenter):4108 ;下对齐(xlBottom):-4107
cell->setProperty("WrapText", true);
// 内容过多,自动换行
//cell->dynamicCall("ClearContents()");
// 清空单元格内容
QAxObject* interior =
cell->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)); //设置单元格字体颜色(红色)
//设置单元格内容,并合并单元格(第5行第3列-第8行第5列)
QAxObject *cell_5_6 =
workSheet->querySubObject("Cells(int,int)", 5, 3);
cell_5_6->setProperty("Value", "Java");
//设置单元格值
QAxObject *cell_8_5 =
workSheet->querySubObject("Cells(int,int)", 8, 5);
cell_8_5->setProperty("Value", "C++");
QString merge_cell;
merge_cell.append(QChar(3 - 1 + 'A'));
//初始列
merge_cell.append(QString::number(5));
//初始行
merge_cell.append(":");
merge_cell.append(QChar(5 - 1 + 'A'));
//终止列
merge_cell.append(QString::number(8));
//终止行
QAxObject *merge_range =
workSheet->querySubObject("Range(const QString&)",
merge_cell);
merge_range->setProperty("HorizontalAlignment", -4108);
merge_range->setProperty("VerticalAlignment",
-4108);
merge_range->setProperty("WrapText",
true);
merge_range->setProperty("MergeCells", true);
//合并单元格
//merge_range->setProperty("MergeCells",
false); //拆分单元格
//work_book->dynamicCall("Save()");
//保存文件(为了对比test与下面的test2文件,这里不做保存操作)
work_book->dynamicCall("SaveAs(const QString&)",
"E:\\test2.xlsx"); //另存为另一个文件
workBook->dynamicCall("Close(Boolean)",
false); //关闭文件
excel.dynamicCall("Quit(void)");
//退出
//return a.exec();
}
四、项目实践
将主界面的数据保存到excel,由于保存时间比较长,所以开线程执行该操作。
void SaveReportThread::run()
{
//
在后台线程中使用QAxObject必须先初始化
CoInitializeEx(NULL,
COINIT_MULTITHREADED);
//SaveToExcel();
SaveToWord();
emit
SIGNAL_SaveReportFinish();
}
void SaveReportThread::SaveToExcel()
{
QAxObject* pExcelApp =
new QAxObject("Excel.Application"); //
创建EXCEL对象,启动Excel.exe进程
pExcelApp->setProperty("DisplayAlerts", false);
//
保存时不提示覆盖
//pExcelApp->setProperty("Visible", true);
// 操作时可以看见EXCEL窗口,调试用
// 打开测试报告模板
QAxObject* pWorkBooks =
pExcelApp->querySubObject("WorkBooks");
pWorkBooks->dynamicCall("Open(const QString&)",
QCoreApplication::applicationDirPath() +
"/TestReportTemplate.xlsx");
QAxObject* pWorkBook =
pExcelApp->querySubObject("ActiveWorkBook");
//
如果要保存全部测试报告,先在模板文件中复制多份sheet模板
QAxObject* pWorkSheet =
pWorkBook->querySubObject("WorkSheets(int)", 1);
if (m_bSaveAll)
{
for (int i = 1; i <
m_pMainwindow->m_vecItemList.size(); i++)
pWorkSheet->dynamicCall("Copy(const QVariant&)",
pWorkSheet->asVariant());
}
//
for循环流程兼容保存单个和全部报告
for (int i = 0; i <
m_pMainwindow->m_vecItemList.size(); i++)
{
if (m_bSaveAll)
emit
SIGNAL_ItemSelected(i); // 通知UI切换测试项,同步操作
// 1.修改sheet名称
pWorkSheet =
pWorkBook->querySubObject("WorkSheets(int)", i + 1);
pWorkSheet->dynamicCall("Select()");
// 必须先select当前sheet
pWorkSheet->setProperty("Name",
m_pMainwindow->m_strCurrentItemName);
// 2.填写测试基本信息
int iRow = 2;
pWorkSheet->querySubObject("Cells(int,int)",
iRow++, 2)->setProperty("Value",
QDate::currentDate().toString("yyyy-MM-dd"));
pWorkSheet->querySubObject("Cells(int,int)",
iRow++, 2)->setProperty("Value",
QTime::currentTime().toString());
pWorkSheet->querySubObject("Cells(int,int)",
iRow++, 2)->setProperty("Value", "user");
foreach (QString strInfo, m_listBaseInfo)
pWorkSheet->querySubObject("Cells(int,int)", iRow++,
3)->setProperty("Value", strInfo);
// 3.填写测试项名称和最终结果
iRow = 18;
pWorkSheet->querySubObject("Cells(int,int)",
iRow, 1)->setProperty("Value",
m_pMainwindow->m_strCurrentItemName);
pWorkSheet->querySubObject("Cells(int,int)",
iRow, 2)->setProperty("Value",
m_pMainwindow->m_vecItemList[m_pMainwindow->m_iCurrentItemIndex]->GetTestPassOrFail());
// 4.填写静态参数
iRow = 21;
int iCount =
m_pMainwindow->ui->listStaticParams->count();
// 有需要手工输入的静态参数也写进测试报告中
QVector vecUserParams;
if
(m_pMainwindow->ui->doubleSpinBoxPower->isVisible())
{
QStringList listPower;
listPower.append(C_PARA_Power);
listPower.append(m_pMainwindow->ui->doubleSpinBoxPower->text());
vecUserParams.push_back(listPower);
iCount++;
}
if
(m_pMainwindow->ui->doubleSpinBoxFrequency->isVisible())
{
QStringList listFreq;
listFreq.append(C_PARA_Freq);
listFreq.append(m_pMainwindow->ui->doubleSpinBoxFrequency->text());
vecUserParams.push_back(listFreq);
iCount++;
}
for (int i = 0; i < iCount; i++)
{
QStringList listParam;
if (i <
m_pMainwindow->ui->listStaticParams->count())
listParam =
m_pMainwindow->ui->listStaticParams->item(i)->text().split("=");
// 静态参数框控件中的内容
else
listParam = vecUserParams[i -
m_pMainwindow->ui->listStaticParams->count()];
// 手工输入的参数
if (i >
0)
{
//
除了第一行,每次都要复制前一行再插入一行,因为报告模板中有第一行的模板
QAxObject* pRow =
pWorkSheet->querySubObject("Rows(int)", iRow);
pRow->dynamicCall("Select()");
pRow->dynamicCall("Copy()");
pRow =
pWorkSheet->querySubObject("Rows(int)", ++iRow);
pRow->dynamicCall("Select()");
pRow->dynamicCall("Insert()");
}
pWorkSheet->querySubObject("Cells(int,int)", iRow,
1)->setProperty("Value", listParam[0]);
pWorkSheet->querySubObject("Cells(int,int)", iRow,
2)->setProperty("Value", listParam[1]);
}
// 5.填写结果列表
iRow += 3;
for (int i = 0; i <
m_pMainwindow->ui->tableResult->rowCount(); i++)
{
if (i >
0)
{
//
除了第一行,每次都要复制前一行再插入一行,因为报告模板中有第一行的模板
QAxObject* pRow =
pWorkSheet->querySubObject("Rows(int)", iRow);
pRow->dynamicCall("Select()");
pRow->dynamicCall("Copy()");
pRow =
pWorkSheet->querySubObject("Rows(int)", ++iRow);
pRow->dynamicCall("Select()");
pRow->dynamicCall("Insert()");
}
if
(m_pMainwindow->ui->tableResult->item(i, 0) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
1)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
0)->text());
if
(m_pMainwindow->ui->tableResult->item(i, 1) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
2)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
1)->text());
if
(m_pMainwindow->ui->tableResult->item(i, 2) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
3)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
2)->text());
if
(m_pMainwindow->ui->tableResult->item(i, 3) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
4)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
3)->text());
if
(m_pMainwindow->ui->tableResult->item(i, 4) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
5)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
4)->text());
if
(m_pMainwindow->ui->tableResult->item(i, 5) != NULL)
pWorkSheet->querySubObject("Cells(int,int)", iRow,
6)->setProperty("Value",
m_pMainwindow->ui->tableResult->item(i,
5)->text());
}
// 6.插入成功率图
iRow += 2;
QString strImagePath =
QDir::toNativeSeparators(QCoreApplication::applicationDirPath() +
"/pic.png"); // 必须把路径中的'/'转换成'\\'
emit SIGNAL_ExportPicture(strImagePath);
// 通知UI线程保存成功率图片,同步操作
if (QFile::exists(strImagePath))
{
QImage
image(strImagePath);
double
dRowHeight = pWorkSheet->querySubObject("Cells(int,int)", iRow,
1)->property("Height").toDouble(); //
每一行的高度,单位磅
double
width = image.width() * 0.75;
// 图片相对于左上角偏移的宽度,单位磅
double
height = image.height() * 0.75;
// 图片相对于左上角偏移的高度,单位磅
QAxObject*
pShapes = pWorkSheet->querySubObject("Shapes");
pShapes->dynamicCall("AddPicture(QString&,bool,bool,double,double,double,double)",
strImagePath, false, true, 0, iRow * dRowHeight, width,
height);
QFile::remove(strImagePath);
}
// 调整列宽
QAxObject* pAllCells =
pWorkSheet->querySubObject("Cells()");
pAllCells->dynamicCall("Select()");
pAllCells->querySubObject("EntireColumn()")->dynamicCall("AutoFit()");
pWorkSheet->querySubObject("Cells(int,int)",
1, 1)->dynamicCall("Select()");
// 默认选中第一个单元格
if (!m_bSaveAll)
break;
}
// 默认选中第一个sheet
pWorkSheet =
pWorkBook->querySubObject("WorkSheets(int)", 1);
pWorkSheet->dynamicCall("Select()");
// 另存为测试报告文件
QString ReportPath =
QDir::toNativeSeparators(QCoreApplication::applicationDirPath());
// 必须把路径中的'/'转换成'\\'
if (m_bSaveAll)
ReportPath += "\\TestReport_All.xlsx";
else
ReportPath += "\\TestReport_" +
m_pMainwindow->m_strCurrentItemName + ".xlsx";
pWorkBook->dynamicCall("SaveAs(const QString&)",
ReportPath);
pWorkBook->dynamicCall("Close()");
pWorkBooks->dynamicCall("Close()");
delete pExcelApp;
pExcelApp = NULL;
}
相关文章推荐
- Qt5(minGW版)+Qwt编译和安装
- Qt调试信息分类和qDebug()导出到文…
- Qt中应用STL算法库编译error分析
- QThread finished()信号 wait()方法
- ubuntu下Qt4.8安装
- QT---线程间通信
- Qt :非window子窗体的透明度设置
- QT:给Widget设置背景图片——设置Widget的调色板,调色板使用图片和背景色
- QT进度条
- 可以供MFC调用的,QT实现的DLL(qtwinmigrate实现)
- QT:轻松获取网页源码
- QT:程序忙碌时的进度条——开启时间循环,等结束的时候再退出
- QT:“下载速度柱状图”的模拟实现——思路真好,会动脑筋,连我都有了启发(这个思路好像是通用的)
- 无法关闭的QT程序——思路开阔一下,原来这么简单!
- QT:窗口最小化时显示一个小浮标
- QT:浮动的饼状统计图(自绘不规则窗口)
- 在QTableView中使用各种自定义委托
- QT:使用“状态模式”绘制界面
- Qt中如何 编写插件 加载插件 卸载插件
- QT:用QSet储存自定义结构体的问题——QSet和STL的set是有本质区别的,QSet是基于哈希算法的,要求提供自定义==和qHash函数