• Qt 操作Excel


    Qt对Excel的数据读/写操作没有现存的类,需要使用QAxObject,下面是从网上下载下来的一个封装好的类,感觉还可以,一般情况下够用,拿来给大家分享。

    头文件:

    #ifndef EXCELENGINE_H
    #define EXCELENGINE_H

    #include <QObject>
    #include <QFile>
    #include <QString>
    #include <QStringList>
    #include <QVariant>
    #include <QAxBase>
    #include <QAxObject>
    #include <QTableWidget>
    #include <QTableView>
    #include <QTableWidgetItem>
    #include <QDebug>
    typedef unsigned int UINT;
    /**
    *@brief 这是一个便于Qt读写excel封装的类,同时,便于把excel中的数据
    *显示到界面上,或者把界面上的数据写入excel中,同GUI进行交互,关系如下:
    *Qt tableWidget <--> ExcelEngine <--> xls file.
    *
    *@note ExcelEngine类只负责读/写数据,不负责解析,做中间层
    *@author yaoboyuan 254200341@qq.com
    *@date 2012-4-12
    */
    class ExcelEngine : protected QObject
    {
    public:
    ExcelEngine();
    ExcelEngine(QString xlsFile);
    ~ExcelEngine();
    public:
    bool Open(UINT nSheet = 1,bool visible = false); //打开xls文件
    bool Open(QString xlsFile,UINT nSheet = 1,bool visible = false);
    void Save(); //保存xls报表
    void Close(); //关闭xls报表
    bool SaveDataFrTable(QTableWidget* tableWidget); //保存数据到xls
    bool ReadDataToTable(QTableWidget* tableWidget); //从xls读取数据到ui
    QVariant GetCellData(UINT row,UINT column); //获取指定单元数据
    bool SetCellData(UINT row,UINT column,QVariant data); //修改指定单元数据
        UINT GetRowCount()const;
    UINT GetColumnCount()const;
        bool IsOpen();
    bool IsValid();
    protected:
    void Clear();
    private:
    QAxObject *pExcel; //指向整个excel应用程序
    QAxObject *pWorkbooks; //指向工作簿集,excel有很多工作簿
    QAxObject *pWorkbook; //指向sXlsFile对应的工作簿
    QAxObject *pWorksheet; //指向工作簿中的某个sheet表单
        QString   sXlsFile;      //xls文件路径
    UINT nCurrSheet; //当前打开的第几个sheet
    bool bIsVisible; //excel是否可见
    int nRowCount; //行数
    int nColumnCount; //列数
        int       nStartRow;     //开始有数据的行下标值
    int nStartColumn; //开始有数据的列下标值
        bool      bIsOpen;       //是否已打开
    bool bIsValid; //是否有效
        bool      bIsANewFile;   //是否是一个新建xls文件,用来区分打开的excel是已存在文件还是有本类新建的
    bool bIsSaveAlready;//防止重复保存
    };
    #endif // EXCELENGINE_H

    源文件:
    #include "excelengine.h"
    #include "qt_windows.h"

    ExcelEngine::ExcelEngine()
    {
    pExcel = NULL;
    pWorkbooks = NULL;
    pWorkbook = NULL;
    pWorksheet = NULL;
    sXlsFile = "";
    nRowCount = 0;
    nColumnCount = 0;
    nStartRow = 0;
    nStartColumn = 0;
    bIsOpen = false;
    bIsValid = false;
    bIsANewFile = false;
    bIsSaveAlready = false;
    HRESULT r = OleInitialize(0);
        if (r != S_OK && r != S_FALSE)
    {
    qDebug("Qt: Could not initialize OLE (error %x)", (unsigned int)r);
    }
    }

    ExcelEngine::ExcelEngine(QString xlsFile)
    {
    pExcel = NULL;
    pWorkbooks = NULL;
    pWorkbook = NULL;
    pWorksheet = NULL;
    sXlsFile = xlsFile;
    nRowCount = 0;
    nColumnCount = 0;
    nStartRow = 0;
    nStartColumn = 0;
    bIsOpen = false;
    bIsValid = false;
    bIsANewFile = false;
    bIsSaveAlready = false;
        HRESULT r = OleInitialize(0);
    if (r != S_OK && r != S_FALSE)
    {
    qDebug("Qt: Could not initialize OLE (error %x)", (unsigned int)r);
    }
    }
    ExcelEngine::~ExcelEngine()
    {
    if ( bIsOpen )
    {
    //析构前,先保存数据,然后关闭workbook
    Close();
    }
    OleUninitialize();
    }
    /**
    *@brief 打开sXlsFile指定的excel报表
    *@return true : 打开成功
    * false: 打开失败
    */
    bool ExcelEngine::Open(UINT nSheet, bool visible)
    {
    if(bIsOpen)
    {
    Close();
    }
    nCurrSheet = nSheet;
    bIsVisible = visible;
        if(NULL == pExcel)
    {
    pExcel = new QAxObject("Excel.Application");
    if(pExcel)
    {
    bIsValid = true;
    }
    else
    {
    bIsValid = false;
    bIsOpen = false;
    return bIsOpen;
    }
    pExcel->dynamicCall("SetVisible(bool)", bIsVisible);
    }
        if(!bIsValid)
    {
    bIsOpen = false;
    return bIsOpen;
    }

    if(sXlsFile.isEmpty())
    {
    bIsOpen = false;
    return bIsOpen;
    }
        /*如果指向的文件不存在,则需要新建一个*/
    QFile f(sXlsFile);
    if(!f.exists())
    {
    bIsANewFile = true;
    }
    else
    {
    bIsANewFile = false;
    }

    if(!bIsANewFile)
    {
    pWorkbooks = pExcel->querySubObject("WorkBooks"); //获取工作簿
    pWorkbook = pWorkbooks->querySubObject("Open(QString, QVariant)",sXlsFile,QVariant(0)); //打开xls对应的工作簿
    }
    else
    {
    pWorkbooks = pExcel->querySubObject("WorkBooks"); //获取工作簿
    pWorkbooks->dynamicCall("Add"); //添加一个新的工作薄
    pWorkbook = pExcel->querySubObject("ActiveWorkBook"); //新建一个xls
    }
    pWorksheet = pWorkbook->querySubObject("WorkSheets(int)", nCurrSheet);//打开第一个sheet
        //至此已打开,开始获取相应属性
    QAxObject *usedrange = pWorksheet->querySubObject("UsedRange"); //获取该sheet的使用范围对象
    QAxObject *rows = usedrange->querySubObject("Rows");
    QAxObject *columns = usedrange->querySubObject("Columns");

    //因为excel可以从任意行列填数据而不一定是从0,0开始,因此要获取首行列下标
    nStartRow = usedrange->property("Row").toInt(); //第一行的起始位置
    nStartColumn = usedrange->property("Column").toInt(); //第一列的起始位置
    nRowCount = rows->property("Count").toInt(); //获取行数
    nColumnCount = columns->property("Count").toInt(); //获取列数
        bIsOpen  = true;
    return bIsOpen;
    }
    /**
    *@brief Open()的重载函数
    */
    bool ExcelEngine::Open(QString xlsFile, UINT nSheet, bool visible)
    {
    sXlsFile = xlsFile;
    nCurrSheet = nSheet;
    bIsVisible = visible;
    return Open(nCurrSheet,bIsVisible);
    }

    /**
    *@brief 保存表格数据,把数据写入文件
    */
    void ExcelEngine::Save()
    {
    if(pWorkbook)
    {
    if(bIsSaveAlready)
    {
    return ;
    }
            if(!bIsANewFile)
    {
    pWorkbook->dynamicCall("Save()");
    }
    else /*如果该文档是新建出来的,则使用另存为COM接口*/
    {
    pWorkbook->dynamicCall("SaveAs (const QString&,int,const QString&,const QString&,bool,bool)",
    sXlsFile,56,QString(""),QString(""),false,false);
    }
    bIsSaveAlready = true;
    }
    }
    /**
    *@brief 关闭前先保存数据,然后关闭当前Excel COM对象,并释放内存
    */
    void ExcelEngine::Close()
    {
    Save();//关闭前先保存数据
    if(pExcel && pWorkbook)
    {
    pWorkbook->dynamicCall("Close(bool)", true);
    pExcel->dynamicCall("Quit()");
    delete pExcel;
    pExcel = NULL;
            bIsOpen        = false;
    bIsValid = false;
    bIsANewFile = false;
    bIsSaveAlready = true;
    }
    }

    /**
    *@brief 把tableWidget中的数据保存到excel中
    *@param tableWidget : 指向GUI中的tablewidget指针
    *@return 保存成功与否 true : 成功
    * false: 失败
    */
    bool ExcelEngine::SaveDataFrTable(QTableWidget *tableWidget)
    {
    if(NULL == tableWidget)
    {
    return false;
    }
        if(!bIsOpen)
    {
    return false;
    }
        int tableR = tableWidget->rowCount();
    int tableC = tableWidget->columnCount();

    //获取表头写做第一行
    for(int i=0;i<tableC;i++)
    {
    if(tableWidget->horizontalHeaderItem(i) != NULL)
    {
    this->SetCellData(1,i+1,tableWidget->horizontalHeaderItem(i)->text());
    }
    }
        //写数据
    for(int i=0;i<tableR;i++)
    {
    for(int j=0;j<tableC;j++)
    {
    if(tableWidget->item(i,j) != NULL)
    {
    this->SetCellData(i+2,j+1,tableWidget->item(i,j)->text());
    }
    }
    }
        //保存
    Save();
    return true;
    }
    /**
    *@brief 从指定的xls文件中把数据导入到tableWidget中
    *@param tableWidget : 执行要导入到的tablewidget指针
    *@return 导入成功与否 true : 成功
    * false: 失败
    */
    bool ExcelEngine::ReadDataToTable(QTableWidget *tableWidget)
    {
    if(NULL == tableWidget)
    {
    return false;
    }

    //先把table的内容清空
    int tableColumn = tableWidget->columnCount();
    tableWidget->clear();
    for(int n=0;n<tableColumn;n++)
    {
    tableWidget->removeColumn(0);
    }
        int rowcnt    = nStartRow + nRowCount;
    int columncnt = nStartColumn + nColumnCount;

    //获取excel中的第一行数据作为表头
    QStringList headerList;
    for(int n = nStartColumn;n<columncnt;n++)
    {
    QAxObject* cell = pWorksheet->querySubObject("Cells(int,int)",nStartRow, n);
    if(cell)
    {
    headerList<<cell->dynamicCall("Value2()").toString();
    }
    }

    //重新创建表头
    tableWidget->setColumnCount(nColumnCount);
    tableWidget->setHorizontalHeaderLabels(headerList);

    //插入新数据
    for(int i=nStartRow+1,r=0;i<rowcnt;i++,r++)//行
    {
    tableWidget->insertRow(r); //插入新行
    for(int j=nStartColumn,c=0;j<columncnt;j++,c++)//列
    {
    QAxObject * cell = pWorksheet->querySubObject("Cells(int,int)",i,j);//获取单元格

           //在r新行中添加子项数据
    if(cell)
    {
    tableWidget->setItem(r,c,new QTableWidgetItem(cell->dynamicCall("Value2()").toString()));
    }
    }
    }

    return true;
    }
    /**
    *@brief 获取指定单元格的数据
    *@param row : 单元格的行号
    *@param column : 单元格的列号
    *@return [row,column]单元格对应的数据
    */
    QVariant ExcelEngine::GetCellData(UINT row, UINT column)
    {
    QVariant data;
    QAxObject *cell = pWorksheet->querySubObject("Cells(int,int)",row,column);//获取单元格对象
        if(cell)
    {
    data = cell->dynamicCall("Value2()");
    }
    return data;
    }
    /**
    *@brief 修改指定单元格的数据
    *@param row : 单元格的行号
    *@param column : 单元格指定的列号
    *@param data : 单元格要修改为的新数据
    *@return 修改是否成功 true : 成功
    * false: 失败
    */
    bool ExcelEngine::SetCellData(UINT row,UINT column,QVariant data)
    {
    bool op = false;
    QAxObject *cell = pWorksheet->querySubObject("Cells(int,int)",row,column);//获取单元格对象
        if ( cell )
    {
    QString strData = data.toString(); //excel 居然只能插入字符串和整型,浮点型无法插入
    cell->dynamicCall("SetValue(const QVariant&)",strData); //修改单元格的数据
    op = true;
    }
    else
    {
    op = false;
    }

    return op;
    }
    /**
    *@brief 清空除报表之外的数据
    */
    void ExcelEngine::Clear()
    {
    sXlsFile = "";
    nRowCount = 0;
    nColumnCount = 0;
    nStartRow = 0;
    nStartColumn = 0;
    }
    /**
    *@brief 判断excel是否已被打开
    *@return true : 已打开
    * false: 未打开
    */
    bool ExcelEngine::IsOpen()
    {
    return bIsOpen;
    }
    /**
    *@brief 判断excel COM对象是否调用成功,excel是否可用
    *@return true : 可用
    * false: 不可用
    */
    bool ExcelEngine::IsValid()
    {
    return bIsValid;
    }

    /**
    *@brief 获取excel的行数
    */
    UINT ExcelEngine::GetRowCount()const
    {
    return nRowCount;
    }
    /**
    *@brief 获取excel的列数
    */
    UINT ExcelEngine::GetColumnCount()const
    {
    return nColumnCount;
    }

    简单使用:

    /*
    ExcelEngine excel(QObject::tr("c:\Test.xls")); //创建
    excel.Open(); //打开

    int num = 0;
    for (int i=1; i<=10; i++)
    {
    for (int j=1; j<=10; j++)
    {
    excel.SetCellData(i,j,++num); //修改指定单元数据
    }
    }

    QVarient data = excel.GetCellData(1,1); //访问指定单元格数据
    excel.GetCellData(2,2);
    excel.GetCellData(3,3);
    excel.Save(); //保存
    excel.Close();
    */

    //导入数据到tablewidget中
    /*
    ExcelEngine excel(QObject::tr("c:\Import.xls"));
    excel.Open();
    excel.ReadDataToTable(ui->tableWidget); //导入到widget中
    excel.Close();
    */

    //把tablewidget中的数据导出到excel中
    /*
    ExcelEngine excel(QObject::tr("c:\Export.xls"));
    excel.Open();
    excel.SaveDataFrTable(ui->tableWidget); //导出报表
    excel.Close();
    */

  • 相关阅读:
    接口自动化1-基础知识
    pytest-fixture之conftest.py
    测试人员一定要懂的ADB操作,赶紧来看一看~
    必看!利用装饰器,帮你自动处理异常并优雅实现重跑case
    最全Airtest接口功能介绍和示例总结,新手同学千万不能错过呀!(二)
    总结一波 Redis 面试题,收藏起来!
    IntelliJ IDEA 2020.2.4款 神级超级牛逼插件推荐
    华为 Java 开发编程军规,谁违反谁走
    CTO:再写if-else,逮着罚款1000!
    VSCode 上竟然也能约会,谈对象了???
  • 原文地址:https://www.cnblogs.com/zhangnianyong/p/5063572.html
Copyright © 2020-2023  润新知