借鉴参考文献中的内容,并将其封装成一个ExcelExporter类,除了实现一些基本的写数据的功能,还增加了设置单元格样式、合并单元格的功能。在Qt中使用QAxObject类访问Com组件对象,需要在pro文件中添加下面的内容:
QT +=axcontainer
Excel对象的主要层次结构:
/*!
*新建一个excel表格
*/
bool ExcelExporter::newExcel(const QString &fileName)
{
pApplication = new QAxObject();
bool b = pApplication->setControl("Excel.Application");//连接Excel控件
if(!b)
return false;
pApplication->dynamicCall("SetVisible(bool)", false);//false不显示窗体
pApplication->setProperty("DisplayAlerts", false);//不显示任何警告信息。
pWorkBooks = pApplication->querySubObject("Workbooks");
QFile file(fileName);
if (file.exists())
{
pWorkBook = pWorkBooks->querySubObject("Open(const QString &)", fileName);
}
else
{
pWorkBooks->dynamicCall("Add");
pWorkBook = pApplication->querySubObject("ActiveWorkBook");
}
if(!pWorkBook)
return false;
pSheets = pWorkBook->querySubObject("Sheets");
if(!pSheets)
return false;
pSheet = pSheets->querySubObject("Item(int)", 1);
if(!pSheet)
return false;
return true;
}
/*!
* 设置最后一个Sheet名字
*/
void ExcelExporter::setSheetName(const QString &sheetName)
{
if(pSheet)
pSheet->setProperty("Name", sheetName);
}
/*!
*增加一个sheet表
*/
void ExcelExporter::appendSheet(const QString &sheetName)
{
int sheet_count = pSheets->property("Count").toInt(); //获取工作表数目
QAxObject *pLastSheet = pSheets->querySubObject("Item(int)", sheet_count);//获取最后一个工作表
pSheet = pSheets->querySubObject("Add(QVariant)", pLastSheet->asVariant());
pLastSheet->dynamicCall("Move(QVariant)", pSheet->asVariant());
pSheet->setProperty("Name", sheetName);
}
/*!
*删除一个sheet表
*/
void ExcelExporter::deleteSheet(const int index)
{
QAxObject *sheet = pSheets->querySubObject("Item(int)", index);
if(sheet){
sheet->dynamicCall("delete");
delete sheet;
}
}
/*!
*设置单元格的值
*/
void ExcelExporter::setCellValue(int row, int column, const QString &value)
{
QAxObject *pCell = pSheet->querySubObject("Cells(int,int)", row, column);
if(pCell){
pCell->dynamicCall("Value", value);
pCell->setProperty("WrapText", true); //内容过多,自动换行
delete pCell;
}
}
/*!
*设置单元格背景色
*/
void ExcelExporter::setCellBackground(int row, int column, const QColor &c)
{
QAxObject *pCell = pSheet->querySubObject("Cells(int,int)", row, column);
if(pCell){
QAxObject* interior = pCell->querySubObject("Interior");
interior->setProperty("Color",QVariant::fromValue(c));
delete pCell;
}
}
/*!
* 设置单元边框颜色
*/
void ExcelExporter::setCellBorder(int row, int column, const QColor &c)
{
QAxObject *pCell = pSheet->querySubObject("Cells(int,int)", row, column);
if(pCell){
QAxObject* border = pCell->querySubObject("Borders");
border->setProperty("Color", QVariant::fromValue(c));
delete pCell;
}
}
/*!
* 设置行高
*/
void ExcelExporter::setCellRowHeight(int row, int column, const int h)
{
QAxObject *pCell = pSheet->querySubObject("Cells(int,int)", row, column);
if(pCell){
pCell->setProperty("RowHeight", h); //设置单元格行高
delete pCell;
}
}
/*!
* 设置列宽
*/
void ExcelExporter::setCellColumnWidth(int row, int column, const int w)
{
QAxObject *pCell = pSheet->querySubObject("Cells(int,int)", row, column);
if(pCell){
pCell->setProperty("ColumnWidth", w); //设置单元格列宽
delete pCell;
}
}
/*!
* 合并单元格
* \param begRow 起始行
* \param begCol 起始列
* \param endRow 终止行
* \param endCol 终止列
*/
void ExcelExporter::mergeCell(int begRow, int begCol, int endRow, int endCol)
{
QString merge_cell;
convertToColName(begCol,merge_cell); //初始列
merge_cell.append(QString::number(begRow)); //初始行
merge_cell.append(":");
convertToColName(endCol,merge_cell); //终止列
merge_cell.append(QString::number(endRow)); //终止行
QAxObject *merge_range = pSheet->querySubObject("Range(const QString&)", merge_cell);
if(!merge_range)
return;
merge_range->setProperty("HorizontalAlignment", -4108);
merge_range->setProperty("VerticalAlignment", -4108);
merge_range->setProperty("WrapText", true);
merge_range->setProperty("MergeCells", true); //合并单元格
delete merge_range;
}
/*!
* \brief 把列数转换为excel的字母列号
* \param data 大于0的数
* \return 字母列号,如1->A 26->Z 27 AA
*/
void ExcelExporter::convertToColName(int data, QString &res)
{
if(data <=0 || data >= 65535)
return;
int tempData = data / 26;
int mode = data % 26;
if(tempData > 0 && mode != 0)
{
convertToColName(tempData,res);
convertToColName(mode,res);
}
else if(tempData > 0 && mode == 0)
{
convertToColName(tempData - 1,res);
res += to26AlphabetString(26);
}
else
{
res += to26AlphabetString(data);
}
}
/*!
* \brief 数字转换为26字母
* 1->A 26->Z
* \param data
* \return
*/
QString ExcelExporter::to26AlphabetString(int data)
{
QChar ch = data + 0x40;//A对应0x41
return QString(ch);
}
/*!
*保存
*/
void ExcelExporter::saveExcel(const QString &fileName)
{
pWorkBook->dynamicCall("SaveAs(const QString &)",
QDir::toNativeSeparators(fileName));
pWorkBook->dynamicCall("Close(Boolean)", false); //关闭文件
if (pApplication != NULL)
{
pApplication->dynamicCall("Quit()");
delete pApplication;
pApplication = NULL;
}
}
本方法下,写入excel表格时间较长,可能会造成程序假死现象,可以重新开启一个线程来处理这个导出过程。
参考文献中给出了一种快速读写Excel表格的方法。文章分析了导致速度满的原因是当对单元格进行读写,每处理一个单元格都要调用一个Excel子对象,如果读写很多单元格时候,就会造成反复调用而不析构,就会导致处理速度慢。
读取慢的根源就在于sheet->querySubObject("Cells(int, int)", row, col)
试想有10000个单元就得调用10000次querySubObject
,网络上90%的教程都没说这个querySubObject
产生的QAxObject*
最好进行手动删除,虽然在它的父级QAxObject
会管理它的内存,但父级不析构,子对象也不会析构,若调用10000次,就会产生10000个QAxObject
对象
参考文献: