欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt:Qt导出Excel表格

程序员文章站 2024-03-17 19:38:34
...

      借鉴参考文献中的内容,并将其封装成一个ExcelExporter类,除了实现一些基本的写数据的功能,还增加了设置单元格样式、合并单元格的功能。在Qt中使用QAxObject类访问Com组件对象,需要在pro文件中添加下面的内容:

QT       +=axcontainer


Excel对象的主要层次结构:

Qt:Qt导出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对象 



   参考文献:

     Qt导出excel

        COM组件开发

       Qt快速读写Excel


相关标签: qt Excel