Qt读写Excel--QXlsx通过Document对象操作工作表3

8 篇文章 61 订阅

Qt读写Excel–QXlsx通过Document对象操作工作表3🌍

更多精彩内容
👉个人内容分类汇总 👈
👉Qt读写Excel–QXlsx基本使用1👈
👉Qt读写Excel–QXlsx编译为静态库2👈
👉Qt读写Excel–QXlsx通过Document对象操作工作表3👈

1、概述🧭

  • QXlsx是一个可以读写Excel文件的库。不依赖office以及wps组件,可以在Qt5支持的任何平台上使用;

  • 使用方式

    1. QXlsx可以编译为动态库使用(使用动态库不用每次的编译,也可以让项目代码量更少,不用一打开工程就几十个文件);
    2. 直接将QXlsx.pri加入代码中使用(我比较推荐直接使用源码,因为QXlsx的注释信息基本在cpp文件中,可以通过阅读源码和注释来学习QXlsx的功能,当然,如果你已经熟悉了QXlsx的使用方式那编译成库使用会更方便,可以使工程的代码量变少);
  • 本文中实现的功能:

    1. 查询打开的Excel中所有可用的工作表(Sheet)名称;
    2. 创建指定名称的工作表(Sheet),自动添加到最末尾,支持ST_WorkSheet、ST_ChartSheet两种类型;
    3. 在指定位置插入一个新的指定名称的工作表(Sheet),支持ST_WorkSheet、ST_ChartSheet两种类型;
    4. 将某个工作表(Sheet)设置为当前活动工作表,并写入数据(ST_WorkSheet类型);
    5. 将指定名称的工作表(Sheet)重命名为一个新的名称,不改变其它因素;
    6. 将指定名称的工作表(Sheet)拷贝为一个新的指定名称的工作表,两个工作表内容相同;
    7. 将指定名称的工作表(Sheet)移动到指定位置;
    8. 删除指定名称的工作表(Sheet)。

2、准备工作🌋

  • 👉👉👉👉👉👉👉看前几章内容。

3、函数说明🗻

注意:执行了操作要保存才生效。⛔

  • QStringList sheetNames() const
    • 功能说明: 查询Excel中所有的工作表(Sheet)名称;
    • 返回值: 所有工作表的名称列表;
  • bool addSheet(const QString &name = QString(), AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet)
    • 功能说明: 在末尾创建一个名称为name,类型为type的工作表;
    • 参数name: 创建的工作表的名称;
    • 参数type: 创建的工作表的类型,可省略;
      • ST_WorkSheet:表格工作表
      • ST_ChartSheet:图表工作表
      • ST_DialogSheet:还不支持
      • ST_MacroSheet:还不支持
    • 返回值: 创建成功则返回true,失败返回false;
      • 如果名称已存在则创建失败;
      • 如果是ST_DialogSheet、ST_MacroSheet也创建失败;(注意这种创建失败有bug,创建失败后输入的name会被保存,下次不能再创建这个名称的工作表,不过不影响使用, 修复方法:xlsxworkbook.cpp文件中的Q_ASSERT(false);下一行添加return sheet;即可)
  • bool insertSheet(int index, const QString &name = QString(), AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet)
    • 功能说明: 在指定位置插入工作表,可设置工作表名称和类型
    • 参数index: 插入工作表的位置,如果>=0则在开始位置插入工作表,如果0<index<sheet总数则在指定位置插入工作表;
    • 参数name: 工作表名称;
    • 参数type: 工作表类型;
    • 返回值: 插入成功返回true,失败返回false;
      • 失败原因与addSheet相同;
      • 如果插入工作表位置>工作表总数则插入失败;
  • bool selectSheet(const QString &name)
    • 功能说明: 将指定名称的工作表设置未活动工作表(可编辑);
    • 参数name: 工作表名称;
    • 返回值: 设置成功返回true,失败返回false;
      • 如果指定名称的工作表不存在则设置失败;
  • bool renameSheet(const QString &oldName, const QString &newName)
    • 功能说明: 将名为oldName的工作表重命名未newName;
    • 参数oldName: 已有工作表名称;
    • 参数newName: 重命名后的工作表名称;
    • 返回值: 重命名成功返回true,失败返回false;
      • 如果oldName不存在则重命名失败;
      • 如果newName已存在则重命名失败;
      • 如果oldName等于newName则重命名失败;
  • bool copySheet(const QString &srcName, const QString &distName = QString())
    • 功能说明: 将指定的srcName工作表拷贝为distName,两个工作表内容相同;
    • 参数srcName: 已有的需要拷贝的工作表名称;
    • 参数distName: 拷贝后的工作表名称;
    • 返回值: 拷贝成功返回true,失败返回false;
      • 如果srcName不存在则拷贝失败;
      • 如果distName已存在则拷贝失败;
      • 如果srcName等于distName则拷贝失败;
  • bool moveSheet(const QString &srcName, int distIndex)
    • 功能说明: 根据输入的工作表名称,将工作表移动到指定位置;
    • 参数srcName: 需要移动的工作表名称;
    • 参数distIndex: 需要将工作表移动到的位置,distIndex<=0则移动到开始位置,distIndex>=sheet总数则移动到最后位置,如果0< distIndex <sheet总数则移动到指定位置;
    • 返回值: 移动成功返回true,失败返回false;
      • 如果需要移动的工作表名称不存在则失败;
  • bool deleteSheet(const QString &name)
    • 功能说明: 删除指定名称的工作表;
    • 参数name: 需要参数的工作表名称;
    • 返回值: 删除成功返回true,失败返回false;
      • 如果指定名称的工作表不存在则返回失败。

4、示例代码⛲

4.1 .h文件🌄

#ifndef TEST2_H
#define TEST2_H

#include <QWidget>
#include "xlsxdocument.h"

namespace Ui {
class Test2;
}

class Test2 : public QWidget
{
    Q_OBJECT

public:
    explicit Test2(QWidget *parent = nullptr);
    ~Test2();

private slots:
    void on_but_open_clicked();

    void on_but_querySheet_clicked();

    void on_but_addSheet_clicked();

    void on_but_insert_clicked();

    void on_but_select_clicked();

    void on_but_rename_clicked();

    void on_but_close_clicked();

    void on_but_copy_clicked();

    void on_but_move_clicked();

    void on_but_delete_clicked();

private:
    Ui::Test2 *ui;

    QXlsx::Document* m_xlsx = nullptr;
};

#endif // TEST2_H

4.2 .cpp文件🌇

#include "test2.h"
#include "ui_test2.h"
#include <QDebug>
#include <QMetaEnum>
#include "xlsxabstractsheet.h"

QXLSX_USE_NAMESPACE            // 添加Xlsx命名空间
#define EXCEL_NAME "./1.xlsx"  // 本demo中用到的excel文件路径文件名

Test2::Test2(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Test2)
{
    ui->setupUi(this);

    this->setWindowTitle("QXlsx中通过Document对象操作工作表Demo");
}

Test2::~Test2()
{
    on_but_close_clicked();
    delete ui;
}

#if 0            // 使用到的函数
QStringList sheetNames() const;
bool addSheet(const QString &name = QString(),
              AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet);
bool insertSheet(int index, const QString &name = QString(),
                 AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet);
bool selectSheet(const QString &name);
bool renameSheet(const QString &oldName, const QString &newName);
bool copySheet(const QString &srcName, const QString &distName = QString());
bool moveSheet(const QString &srcName, int distIndex);
bool deleteSheet(const QString &name);
#endif

/**
 * @brief 打开Excel
 */
void Test2::on_but_open_clicked()
{
    if(!m_xlsx)
    {
        m_xlsx = new Document(EXCEL_NAME, this);        // 打开EXCEL_NAME文件,将所有数据读取到内存中,然后关闭excel文件
    }
    if(m_xlsx->load())  // 判断文件是否打开成功(也可以使用isLoadPackage)
    {
        qInfo() << "excel打开成功!";
        // 基于范围的for从容器中获取迭代器。但是因为容器不是const迭代器,所以迭代器将是非的const,这显然足以让容器分离
        const QList<QWidget*> objects =  this->findChildren<QWidget*>();
        for(auto object: objects)
        {
            object->setEnabled(true);
        }
    }
    else
    {
        qWarning() << "excel打开失败!";
    }
}

/**
 * @brief 释放Excel内存
 */
void Test2::on_but_close_clicked()
{
    if(m_xlsx)
    {
        delete m_xlsx;
        m_xlsx = nullptr;
        const QList<QWidget*> objects =  this->findChildren<QWidget*>();
        for(auto object: objects)
        {
            object->setEnabled(false);
        }
        ui->widget1->setEnabled(true);
        ui->but_open->setEnabled(true);
    }
}

/**
 * @brief 查询Excel中所有的工作表(Sheet)名称
 */
void Test2::on_but_querySheet_clicked()
{
    ui->com_sheets->clear();
    ui->com_sheets->addItems(m_xlsx->sheetNames());
}

/**
 * @brief 创建不同类型的工作表
 *        QXlsx 的SheetType定义了四种类型,但是目前只支持ST_WorkSheet, ST_ChartSheet两种;
 *        如果创建了不支持的两种在Debug模式下会报错(Q_ASSERT断言),在Release下会返回失败;
 *        注意:这里有一个小bug
 *        由于还不支持ST_DialogSheet和ST_MacroSheet;
 *        如果在Release模式下如果创建了ST_DialogSheet或者ST_MacroSheet将会失败,
 *        而Q_ASSERT在Release下如果失效则会导致sheetNames添加未创建的sheetName;
 *
 */
void Test2::on_but_addSheet_clicked()
{
    QString strName = ui->line_sheetName->text();
    if(strName.isEmpty())
    {
        qWarning() << "工作表名称不能为空!";
        return;
    }
    AbstractSheet::SheetType type = (AbstractSheet::SheetType)ui->com_sheetType->currentIndex();
    bool ret = m_xlsx->addSheet(strName, type);         // 创建一个新的工作表,参数二可以省略
    if(ret && m_xlsx->save())                           // 执行完操作后需要保存到原有Excel中,不保存则无效
    {
        qInfo() << QString("创建工作表:%1  %2 成功!").arg(strName).arg(type);
    }
    else
    {
        qWarning() << QString("创建工作表:%1  %2 失败!").arg(strName).arg(type);
    }
}

/**
 * @brief 在指定位置插入工作表,可设置工作表名称和类型
 */
void Test2::on_but_insert_clicked()
{
    QString strName = ui->line_sheetName->text();
    if(strName.isEmpty())
    {
        qWarning() << "工作表名称不能为空!";
        return;
    }
    AbstractSheet::SheetType type = (AbstractSheet::SheetType)ui->com_sheetType->currentIndex();
    int index = ui->spin_index->value();
    bool ret = m_xlsx->insertSheet(index, strName, type);
    if(ret && m_xlsx->save())
    {
        qInfo() << QString("在%1位置插入工作表:%2  %3 成功!").arg(index).arg(strName).arg(type);
    }
    else
    {
        qWarning() << QString("在%1位置插入工作表:%2  %3 失败!").arg(index).arg(strName).arg(type);
    }
}

/**
 * @brief 将输入名称的工作表设置为活动工作表,并写入数据,如果工作表不存在或者不是ST_WorkSheet类型则不写入
 */
void Test2::on_but_select_clicked()
{
    QString strName = ui->line_sheetName->text();
    if(strName.isEmpty())
    {
        qWarning() << "工作表名称不能为空!";
        return;
    }
    bool ret = m_xlsx->selectSheet(strName);          // 将strName设置为活动工作表
    if(ret)
    {
        qInfo() << QString("设置活动工作表%1成功!").arg(strName);
        AbstractSheet::SheetType type = m_xlsx->currentSheet()->sheetType();   // 获取当前工作表的类型
        if(type == AbstractSheet::ST_WorkSheet)
        {
            ret = m_xlsx->write(1, 1, "设置获取工作表!");
            if(ret && m_xlsx->save())
            {
                qInfo() << "将数据写入选择的工作表成功!";
            }
            else
            {
                qInfo() << "将数据写入选择的工作表失败!";
            }
        }
        else
        {
            qInfo() << "其它类型sheet,不写入数据";
        }
    }
    else
    {
        qWarning() << QString("设置活动工作表%1失败,可能不存在!").arg(strName);
    }
}

/**
 * @brief 重命名sheet
 */
void Test2::on_but_rename_clicked()
{
    QString strName = ui->line_sheetName->text();
    if(strName.isEmpty())
    {
        qWarning() << "工作表名称不能为空!";
        return;
    }
    QString strNewName = ui->line_newSheetName->text();
    if(strNewName.isEmpty())
    {
        qWarning() << "新的工作表名称不能为空!";
        return;
    }
    bool ret = m_xlsx->renameSheet(strName, strNewName);
    if(ret && m_xlsx->save())
    {
        qInfo() << QString("将%1重命名为%2成功!").arg(strName, strNewName);
    }
    else
    {
        qWarning() << QString("将%1重命名为%2失败!").arg(strName, strNewName);
    }
}

/**
 * @brief 将指定的strName工作表拷贝为strNewName,如果strNewName已存在则拷贝失败
 */
void Test2::on_but_copy_clicked()
{
    QString strName = ui->line_sheetName->text();
    if(strName.isEmpty())
    {
        qWarning() << "工作表名称不能为空!";
        return;
    }
    QString strNewName = ui->line_newSheetName->text();
    if(strNewName.isEmpty())
    {
        qWarning() << "新的工作表名称不能为空!";
        return;
    }
    bool ret = m_xlsx->copySheet(strName, strNewName);       // 开始拷贝工作表
    if(ret && m_xlsx->save())
    {
        qInfo() << QString("将%1拷贝为%2成功!").arg(strName, strNewName);
    }
    else
    {
        qWarning() << QString("将%1拷贝为%2失败!").arg(strName, strNewName);
    }
}

/**
 * @brief 根据输入的工作表名称,将工作表移动到指定位置,如果工作表不存在或移动到当前位置则失败
 *        移动位置从0开始,如果大于sheet总数则移动到最后位置,如果小于0则移动到最开始位置
 */
void Test2::on_but_move_clicked()
{
    QString strName = ui->line_sheetName->text();
    if(strName.isEmpty())
    {
        qWarning() << "工作表名称不能为空!";
        return;
    }
    int index = ui->spin_index->value();
    bool ret = m_xlsx->moveSheet(strName, index);        // 开始移动工作表位置
    if(ret && m_xlsx->save())
    {
        qInfo() << QString("将%1移动到%2位置成功!").arg(strName).arg(index);
    }
    else
    {
        qWarning() << QString("将%1移动到%2位置失败!").arg(strName).arg(index);
    }
}

/**
 * @brief 删除指定名称的工作表,如果指定名称的工作表不存在则返回失败
 */
void Test2::on_but_delete_clicked()
{
    QString strName = ui->line_sheetName->text();
    if(strName.isEmpty())
    {
        qWarning() << "工作表名称不能为空!";
        return;
    }
    bool ret = m_xlsx->deleteSheet(strName);        // 开始删除
    if(ret && m_xlsx->save())
    {
        qInfo() << QString("删除工作表%1成功!").arg(strName);
    }
    else
    {
        qWarning() << QString("删除工作表%1失败!").arg(strName);
    }
}

5、实现效果🎡

  • 功能较多,没有一一演示

    在这里插入图片描述

6、源代码🏠

gitee
github

⛹🏋🚴🤸🤸‍♂️🤼🤾

  • 11
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
Qt是一个跨平台的C++开发框架,提供了许多操作文件和格的函数和类。要使用Qt操作Excel格的书签,需要先安装并配置Qt的相关库。 首先,需要在Qt中引入相关的库。Qt提供了QAxObject类,用于操作COM组件。在Qt项目中,需要在.pro文件中添加`QT += axcontainer`以引入该库。 接下来,可以使用QAxObject的相关函数来读写Excel格书签。首先,需要创建QAxObject对象,并调用其setControl函数来指定COM组件。在这里,我们需要指定Excel的COM组件: ```cpp QAxObject* excel = new QAxObject("Excel.Application"); ``` 然后,可以使用QAxObject的函数打开Excel格,并获取工作簿和工作: ```cpp QAxObject* workbooks = excel->querySubObject("Workbooks"); QAxObject* workbook = workbooks->querySubObject("Open(const QString&)", filePath); QAxObject* sheets = workbook->querySubObject("Worksheets"); QAxObject* sheet = sheets->querySubObject("Item(int)", sheetIndex); ``` 在获取到工作后,可以使用QAxObject的相应函数操作Excel格书签。具体的操作方法和函数,请参考Microsoft Excel的官方文档。 最后,记得在使用完Excel后,调用相应的销毁函数来释放资源: ```cpp sheet->dynamicCall("Close()"); excel->dynamicCall("Quit()"); delete excel; ``` 这样,就可以使用Qt操作Excel格书签了。需要注意的是,要确保计算机上安装了Microsoft Office并启用了相关功能。并且,在使用COM组件时要及时关闭和释放资源,以避免资源泄露。 总的来说,使用Qt操作Excel格书签需要引入QAxObject类,并进行相应的函数调用。遵循以上步骤,可以顺利地读写Excel格书签。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mahuifa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值