Qt读写Execl:QXlsx库

Qt三方库开发技术:QXlsx介绍、编译和使用

我自己记录的实例代码:https://download.csdn.net/download/cao_jie_xin/88795216

目录

  • 一、概述
  • 二、下载
  • 三、编译
  • 四、加载QXlsx静态库
  • 五、介绍一些常用的功能
    • 1、一些头文件和命名空间
    • 2、创建一个excel文件
    • 3、打开文件并判断是否打开成功
    • 4、使用两种不同的方式将数据写入excel,未指定sheet则默认为sheet1
    • 5、读取excel中所有数据
    • 6、释放数据
    • 7、在指定位置插入工作表,可设置工作表名称和类型
    • 8、将输入名称的工作表设置为活动工作表
    • 9、重命名sheet
    • 10、将指定的strName工作表拷贝为strNewName,如果strNewName已存在则拷贝失败
    • 11、根据输入的工作表名称,将工作表移动到指定位置
    • 12、删除指定名称的工作表
    • 13、创建指定名称的工作表(Sheet),自动添加到最末尾
    • 14、查询所有可用工作表
    • 15、查询选中工作表的状态(显示、隐藏、绝对隐藏)
    • 16、设置工作表状态
    • 17、在工作表中插入图表
    • 18、在当前Sheet指定位置插入图片
    • 19、获取当前Sheet中图片个数
    • 20、通过索引方式和行列号方式读取当前Sheet中的图片
    • 21、演示三种方式的单元格合并
    • 22、取消合并单元格
    • 23、在不修改其它内容情况下设置单元格水平对齐
    • 24、在不修改其它内容情况下设置单元格垂直对齐
    • 25、通过索引号设置数字格式
    • 26、设置自定义数字格式
    • 27、设置字体样式
    • 28、设置列宽或者行高
    • 29、设置单元格样式

一、概述

QXlsx是一个可以读写Excel文件的库。它不需要Microsoft Excel,可以在Qt5支持的任何平台上使用。
库支持的功能:

  • 创建新的xlsx文件;
  • 从.xlsx文件中提取数据
  • 编辑现有的.xlsx文件

QXlsx和QAxObject 读写Excel比较

  • QAxObject使用需要系统中安装了offie或wps,这种方法不推荐使用;
    因为如果安装了wps,可能部分功能用不了;
    同时安装了office、wps在使用时可能有问题;
    或者电脑里安装了一些pdf阅读器则直接不能使用了;

  • QXlsx不依赖于系统环境,使用时打开excel文件将所有数据读入内存,然后就关闭文件了,也不存在文件被占用的情况。

二、下载

github官网:https://github.com/QtExcel/QXlsx

三、编译

打开QXlsx工程:进入QXlsx文件夹,双击打开QXlsx.pro工程文件
在这里插入图片描述
在这里插入图片描述
在Pro文件中删除 TARGET = QXlsx,然后加入下列代码,这些代码是将编译后的静态库全部放到一个文件夹下,不用我们自己去拷,同时在编译debug版本静态库时在名称后面加一个 d 用于区分,防止debug静态库覆

1 contains(QT_ARCH, i386){        # 使用32位编译器
2 DESTDIR = $$PWD/bin             # 程序输出路径
3 }else{
4 message("64bit")                # 使用64位编译器
5 DESTDIR = $$PWD/bin64
6 }
7 win32:CONFIG(release, debug|release): TARGET = QXlsx        # 生成release版本静态库名称
8 else:win32:CONFIG(debug, debug|release): TARGET = QXlsxd    # 生成debug版本静态库名称

在这里插入图片描述
分别选择Debug、Release,然后点击左下角的锤子
在这里插入图片描述
编译完成后,在QXlsx文件夹下就会出现一个bin64文件夹,打开文件夹就可以看见有QXlsx.libQXlsxd.lib两个文件
在这里插入图片描述
在这里插入图片描述
新建一个QXlsx文件夹,将header文件夹和bin64文件夹拷贝到新建的QXlsx文件夹中,然后将header重命名为include,到这里编译的QXlsx就准备完成了。
在这里插入图片描述

四、加载QXlsx静态库

新建一个Qt工程,将准备好的QXlsx文件夹拷贝到工程目录下
在这里插入图片描述
在QtCreator中鼠标在工程上右键选择添加库
在这里插入图片描述
选择外部库
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/10d0eb7759de4afaaaf9c01037f3f498.png
点击浏览,找到工程路径下的QXlsx.lib库,选择Window、为debug版本添加‘d’作为后缀

在这里插入图片描述
点击下一步后就会在Pro文件中生成下列内容,到这一步就加载完成了。
在这里插入图片描述


测试QXlsx静态库
在工程中添加下列代码,然后分别以debug、release模式编译,如果在生成的可执行程序路径下看见Test.xlsx文件了,那就说明QXlsx静态库 编译成功了

#include "widget.h"
#include "ui_widget.h"

#include "xlsxdocument.h"           // 添加QXlsx头文件

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

    QXlsx::Document xlsx;           // 创建一个excel
    xlsx.write("A1", "Hello Qt!");  // 在第一行第一列写入数据
    xlsx.saveAs("Test.xlsx");       // excel保存到./Test.xlsx
}

Widget::~Widget()
{
    delete ui;
}

五、介绍一些常用的功能

1、一些头文件和命名空间

#include "xlsxdocument.h"
#include "xlsxchartsheet.h"
#include "xlsxcellrange.h"
#include "xlsxchart.h"

QXLSX_USE_NAMESPACE            // 添加QXlsx命名空间

2、创建一个excel文件

	Document xlsx;                      // 初始化后默认有一个sheet1
	//doc.addSheet("第一个sheet", AbstractSheet::ST_WorkSheet);  // 添加第一个sheet,如果不添加则会有一个默认的
    bool ret = xlsx.saveAs(EXCEL_NAME); // 保存到EXCEL_NAME,如果已经存在则覆盖
    if(ret)
    {
        qInfo() << "创建excel成功!";
    }
    else
    {
        qWarning() << "创建excel失败!";
    }

3、打开文件并判断是否打开成功

QXlsx::Document* m_xlsx = nullptr;
	if(!m_xlsx)
    {
        m_xlsx = new Document(EXCEL_NAME, this);        // 打开EXCEL_NAME文件,将所有数据读取到内存中,然后关闭excel文件
    }
    if(m_xlsx->load())  // 判断文件是否打开成功(也可以使用isLoadPackage),如果文件不存在则为false
    {
        qInfo() << "excel打开成功!";
    }
    else
    {
        qWarning() << "excel打开失败!";
    }

4、使用两种不同的方式将数据写入excel,未指定sheet则默认为sheet1

#if 0
    m_xlsx->write("A2", 123);         // 从A1开始
    m_xlsx->write("B2", 0.001);
    m_xlsx->write("C2", "abc");
    m_xlsx->write("D2", true);
    m_xlsx->write("E2", "你好");
#else
    m_xlsx->write(1, 1, 456);        // 从1,1开始
    m_xlsx->write(1, 2, 0.002);
    m_xlsx->write(1, 3, "aaa");
    m_xlsx->write(1, 4, false);
    m_xlsx->write(1, 5, "阿斯蒂芬");
#endif
    if(m_xlsx->save())
    {
        qInfo() << "数据写入成功!";
    }
    else
    {
        qWarning() << "数据写入失败!";
    }

5、读取excel中所有数据

    int rowLen = m_xlsx->dimension().rowCount();           // 获取最大行数
    int columnLen = m_xlsx->dimension().columnCount();     // 获取最大列数
    for(int i = 1; i <= rowLen; i++)                       // 遍历每一行
    {
        QString data = QString("第%1行:").arg(i);
        for(int j = 1; j <= columnLen; j++)                // 遍历每一个单元格(列)
        {
#if 1
            QVariant value = m_xlsx->read(i, j);                                         // 通过单元格行号、列号读取数据
#else
            QVariant value = m_xlsx->read(QString("%1%2").arg((char)(64 + i)).arg(j));   // 通过单元格引用读取数据
#endif
            if(!value.isNull())
            {
                data.append(value.toString()).append(" ");
            }
            else
            {
                data.append("NULL ");
            }
        }
        qInfo() << data;
    }

6、释放数据

if(m_xlsx)
{
    delete m_xlsx;
    m_xlsx = nullptr;
}

7、在指定位置插入工作表,可设置工作表名称和类型

int index = 2;
    QString strName = "第二个sheet";
    AbstractSheet::SheetType type = AbstractSheet::ST_WorkSheet;

    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);
    }

8、将输入名称的工作表设置为活动工作表

QString strName = "第二个sheet";
bool ret = m_xlsx->selectSheet(strName);          // 将strName设置为活动工作表

9、重命名sheet

QString strName = "第二个sheet";
QString strNewName = "第三个sheet";
bool ret = m_xlsx->renameSheet(strName, strNewName);

10、将指定的strName工作表拷贝为strNewName,如果strNewName已存在则拷贝失败

QString strName = "第二个sheet";
QString strNewName = "第三个sheet";
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);
}

11、根据输入的工作表名称,将工作表移动到指定位置

如果工作表不存在或移动到当前位置则失败,移动位置从0开始,如果大于sheet总数则移动到最后位置,如果小于0则移动到最开始位置。

QString strName = "第二个sheet";
    int index = 2;
    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);
    }

12、删除指定名称的工作表

如果指定名称的工作表不存在则返回失败

QString strName = "第二个sheet";
    bool ret = m_xlsx->deleteSheet(strName);        // 开始删除
    if(ret && m_xlsx->save())
    {
        qInfo() << QString("删除工作表%1成功!").arg(strName);
    }
    else
    {
        qWarning() << QString("删除工作表%1失败!").arg(strName);
    }

13、创建指定名称的工作表(Sheet),自动添加到最末尾

Document xlsx(EXCEL_NAME);             // 如果文件存在则打开EXCEL_NAME,如果不存在则传入文件名,在save时保存为EXCEL_NAME
    qDebug() << xlsx.load();               // 如果文件存在,并且打开成功则为true,否则为false
    //    xlsx.addSheet();                     // 创建一个工作表,如果没指定名称则默认为Sheet1、Sheet2递增
    xlsx.addSheet("第二个sheet");  // 指定名称创建工作表(默认设置为当前活动工作表)

14、查询所有可用工作表

Document xlsx(EXCEL_NAME);
QStringList n = xlsx.sheetNames();

15、查询选中工作表的状态(显示、隐藏、绝对隐藏)

QString strName = "第二个sheet";
    Document xlsx(EXCEL_NAME);
    AbstractSheet* sheet = xlsx.sheet(strName);   // 根据名称获取工作表指针
    if(!sheet) return;    // 判断是否为NULL

    int state = sheet->sheetState();           // 获取当前工作表状态

16、设置工作表状态

可通过setSheetState设置显示、隐藏、绝对隐藏【三种状态】,通过sheetState获取工作表当前状态【三种状态】
也可以通过setHiddensetVisible设置显示、隐藏状态【两种状态】,并通过isHidden或者isVisible查询显示隐藏状态【两种状态】

QString strName = "第二个sheet";
    Document xlsx(EXCEL_NAME);
    AbstractSheet* sheet = xlsx.sheet(strName);   // 根据名称获取工作表指针
    if(!sheet) return;    // 判断是否为NULL

    int index = 0;
    sheet->setSheetState(AbstractSheet::SheetState(index));             // 修改工作表状态

17、在工作表中插入图表

这里演示了Qxlsx中所有图表类型;
从源码中void ChartPrivate::saveXmlChart(QXmlStreamWriter &writer) const函数看,部分ChartType类型还不支持,如CT_StockChart

Document xlsx;                    // 创建一个Excel对象(默认有一个Sheet1)
    for(int i = 1; i < 10; i++)
    {
        xlsx.write(i, 1, i * i * i);    // 在第一列写入9个数据
        xlsx.write(i, 2, i * i);       // 在第二列写入9个数据
        xlsx.write(i, 3, i *i - 1);    // 写入第三列数据
    }
    qDebug() << CellReference(1, 2).toString();                    // 可将行列号转换为【字符串】单元格引用

    // 插入面积图
    xlsx.write(3, 4, "CT_AreaChart");  // 在图标左上角单元格中写入图标的类型
    Chart* areaChart = xlsx.insertChart(3, 3, QSize(300, 300));
    areaChart->setChartType(Chart::CT_AreaChart);
    areaChart->addSeries(CellRange("A1:C9"));

    // 插入3D面积图(在WPS中显示存在问题,office没有测试)
    xlsx.write(3, 10, "CT_Area3DChart");
    Chart *area3DChart = xlsx.insertChart(3, 9, QSize(300, 300));
    area3DChart->setChartType(Chart::CT_Area3DChart);
    area3DChart->addSeries(CellRange("A1:C9"));

    // 插入折线图
    xlsx.write(3, 16, "CT_LineChart");
    Chart* lineChart = xlsx.insertChart(3, 15, QSize(300, 300));
    lineChart->setChartType(Chart::CT_LineChart);
    lineChart->addSeries(CellRange("A1:C9"));

    // 插入3D折线图
    xlsx.write(23, 4, "CT_Line3DChart");
    Chart* line3DChart = xlsx.insertChart(23, 3, QSize(300, 300));
    line3DChart->setChartType(Chart::CT_Line3DChart);
    line3DChart->addSeries(CellRange("A1:C9"));

    // 插入股价图(貌似还不支持)
    xlsx.write(23, 10, "CT_StockChart");
    Chart* stockChart = xlsx.insertChart(23, 9, QSize(300, 300));
    stockChart->setChartType(Chart::CT_StockChart);
    stockChart->addSeries(CellRange("A1:C9"));

    // 插入雷达图(貌似还不支持)
    xlsx.write(23, 16, "CT_RadarChart");
    Chart* radarChart = xlsx.insertChart(23, 15, QSize(300, 300));
    radarChart->setChartType(Chart::CT_RadarChart);
    radarChart->addSeries(CellRange("A1:A9"));

    // 插入散点图(在WPS中效果和CT_LineChart一样)
    xlsx.write(43, 4, "CT_ScatterChart");
    Chart* scatterChart = xlsx.insertChart(43, 3, QSize(300, 300));
    scatterChart->setChartType(Chart::CT_ScatterChart);
    scatterChart->addSeries(CellRange("A1:A9"));             // 插入三个数据系列
    scatterChart->addSeries(CellRange("B1:B9"));
    scatterChart->addSeries(CellRange("C1:C9"));
    // 散点图不能以A1:C9这种方式同时选择三列数据,在WPS中会默认把第一列数据当做X轴数据,QXlsx中会直接舍弃掉第一列数据,
    // 由addSeries函数中if (d->chartType == CT_ScatterChart || d->chartType == CT_BubbleChart)可看出
    //    scatterChart->addSeries(CellRange("A1:C9"));

    // 插入饼图
    xlsx.write(43, 10, "CT_PieChart");
    Chart* pieChart = xlsx.insertChart(43, 9, QSize(300, 300));    // 在第三行、三列的单元格右下角位置插入一个长宽为300的图表
    pieChart->setChartType(Chart::CT_PieChart);                    // 指定图表类型为【饼图】(支持16种类型图表)
    pieChart->addSeries(CellRange("A1:A9"));                       // 添加饼图的数据系列1(单元格引用字符串方式指定【第一列数据】)
    pieChart->addSeries(CellRange(CellReference(1, 2), CellReference(9, 2))); // 添加饼图数据2(通过CellReference指定【第二列数据】)
    pieChart->addSeries(CellRange(1, 3, 9, 3));                    // 添加饼图数据系列3(通过[开始行列号]和[结束行列号]指定【第三列数据】)

    // 插入3D饼图(这个图表在WPS中样式和CT_PieChart一样,没有表现出3D效果,无法设置三维旋转)
    xlsx.write(43, 16, "CT_Pie3DChart");
    Chart* pie3DChart = xlsx.insertChart(43, 15, QSize(300, 300));
    pie3DChart->setChartType(Chart::CT_Pie3DChart);
    pie3DChart->addSeries(CellRange("A1:A9"));

    // 插入圆环图
    xlsx.write(63, 4, "CT_DoughnutChart");
    Chart* doughnutChart = xlsx.insertChart(63, 3, QSize(300, 300));
    doughnutChart->setChartType(Chart::CT_DoughnutChart);
    doughnutChart->addSeries(CellRange("A1:A9"));

    // 插入柱状图
    xlsx.write(63, 10, "CT_BarChart");
    Chart* barChart = xlsx.insertChart(63, 9, QSize(300, 300));
    barChart->setChartType(Chart::CT_BarChart);
    barChart->addSeries(CellRange("A1:A9"));

    // 插入3D柱状图(在WPS中显示异常,不支持3D柱状图)
    xlsx.write(63, 16, "CT_Bar3DChart");
    Chart* bar3DChart = xlsx.insertChart(63, 15, QSize(300, 300));
    bar3DChart->setChartType(Chart::CT_Bar3DChart);
    bar3DChart->addSeries(CellRange("A1:A9"));

    // 插入饼图(还不支持)
    xlsx.write(83, 4, "CT_OfPieChart");
    Chart* ofPieChart = xlsx.insertChart(83, 3, QSize(300, 300));
    ofPieChart->setChartType(Chart::CT_OfPieChart);
    ofPieChart->addSeries(CellRange("A1:A9"));

    // 插入曲面图(还不支持)
    xlsx.write(83, 10, "CT_SurfaceChart");
    Chart* surfaceChart = xlsx.insertChart(83, 9, QSize(300, 300));
    surfaceChart->setChartType(Chart::CT_SurfaceChart);
    surfaceChart->addSeries(CellRange("A1:A9"));

    // 插入3D曲面图(还不支持)
    xlsx.write(83, 16, "CT_Surface3DChart");
    Chart* surface3DChart = xlsx.insertChart(83, 15, QSize(300, 300));
    surface3DChart->setChartType(Chart::CT_Surface3DChart);
    surface3DChart->addSeries(CellRange("A1:A9"));

    // 插入气泡图(还不支持)
    xlsx.write(103, 4, "CT_BubbleChart");
    Chart* bubbleChart = xlsx.insertChart(103, 3, QSize(300, 300));
    bubbleChart->setChartType(Chart::CT_BubbleChart);
    bubbleChart->addSeries(CellRange("A1:A9"));

    if(xlsx.saveAs(EXCEL_NAME))    // 如果文件已经存在则覆盖
    {
        qInfo() << "插入所有图表Demo保存成功!";
    }
    else
    {
        qWarning() << "插入所有图表Demo保存失败!";
    }
  1. 设置【图例】位置。
  2. 设置图表【标题】。
  3. 打开图表网格线。
  4. 行列交换标头。
  5. 设置插入的数据范围是否包含标题。
  6. 插入图表,引用其它工作表数据。
Document xlsx;

    for(int i = 1; i < 10; i++)
    {
        xlsx.write(1, i + 1, QString("Pos %1").arg(i));      // 写入列标题
        xlsx.write(2, i + 1, i * i * i);                     // 写入数据
        xlsx.write(3, i + 1, i * i);
    }
    // 写入行标题
    xlsx.write(2, 1, "Set 1");
    xlsx.write(3, 1, "Set 2");

    // 插入一个柱状图,并设置图例在【右边】
    xlsx.write(5, 4, "图例在右边");
    Chart* barChart1 = xlsx.insertChart(5, 3, QSize(300, 300));  // 插入图表
    barChart1->setChartType(Chart::CT_BarChart);
    barChart1->setChartLegend(Chart::Right);     // 设置图例在右边,可设置None:无图例, Left:左边, Right:右边, Top:上边, Bottom:下边
    barChart1->setChartTitle("Test1");
    barChart1->addSeries(CellRange(1, 1, 3, 10), nullptr, true, true, false);

    // 插入一个柱状图,启动【主网格线】
    xlsx.write(5, 10, "图例在左边,启动主网格线");
    Chart* barChart2 = xlsx.insertChart(5, 9, QSize(300, 300));  // 插入图表
    barChart2->setChartType(Chart::CT_BarChart);
    barChart2->setChartLegend(Chart::Left);
    barChart2->setChartTitle("Test2");
    barChart2->setGridlinesEnable(true);   // 启动主网格线
    barChart2->addSeries(CellRange(1, 1, 3, 10), nullptr, true, true, false);

    // 插入一个柱状图,启动【次网格线】
    xlsx.write(5, 16, "图例在上边,启动次网格线");
    Chart* barChart3 = xlsx.insertChart(5, 15, QSize(300, 300));  // 插入图表
    barChart3->setChartType(Chart::CT_BarChart);
    barChart3->setChartLegend(Chart::Top);
    barChart3->setChartTitle("Test3");
    barChart3->setGridlinesEnable(false, true);  // 关闭主网格线,启动子网格线
    barChart3->addSeries(CellRange(1, 1, 3, 10), nullptr, true, true, false);

    // 插入一个柱状图,【行列交换标头】
    xlsx.write(25, 4, "图例在下边,行列交换标头");
    Chart* barChart4 = xlsx.insertChart(25, 3, QSize(300, 300));  // 插入图表
    barChart4->setChartType(Chart::CT_BarChart);
    barChart4->setChartLegend(Chart::Bottom);
    barChart4->setChartTitle("Test4");
    barChart4->addSeries(CellRange(1, 1, 3, 10), nullptr, false, true, true);  // 参数5【true:以1列为1个数据系列,false:以1行为1个数据系列】

    // 插入一个柱状图,【数据范围不包含标题】
    xlsx.write(25, 10, "数据范围不包含标题");
    Chart* barChart5 = xlsx.insertChart(25, 9, QSize(300, 300));  // 插入图表
    barChart5->setChartType(Chart::CT_BarChart);
    barChart5->setChartLegend(Chart::Right);
    barChart5->setChartTitle("Test5");
    // 参数1:添加数据系列范围;参数2:指定插入的数据位于哪个工作表(Sheet),默认为NULL,即当前工作表;
    // 参数3,数据系列范围第一行是否为列标题,true:为标题;参数4,数据系列范围第1列是否为行标题,true:为标题;默认都不为标题
    // 参数5:交换行列标头。
    barChart5->addSeries(CellRange(1, 1, 3, 10));

    // 插入一个柱状图,【数据范围包含列标题】
    xlsx.write(25, 16, "数据范围包含列标题");
    Chart* barChart6 = xlsx.insertChart(25, 15, QSize(300, 300));  // 插入图表
    barChart6->setChartType(Chart::CT_BarChart);
    barChart6->setChartLegend(Chart::Right);
    barChart6->setChartTitle("Test6");
    barChart6->addSeries(CellRange(1, 1, 3, 10), nullptr, true);

    // 插入一个柱状图,【数据范围包含行标题】
    xlsx.write(45, 4, "数据范围包含行标题");
    Chart* barChart7 = xlsx.insertChart(45, 3, QSize(300, 300));  // 插入图表
    barChart7->setChartType(Chart::CT_BarChart);
    barChart7->setChartLegend(Chart::Right);
    barChart7->setChartTitle("Test7");
    barChart7->addSeries(CellRange(1, 1, 3, 10), nullptr, false, true);

    // 添加一个工作表(Sheet2),在Sheet2中插入图表,数据为Sheet1中的数据
    xlsx.addSheet("Sheet2");                                     // 添加一个工作表,当前工作表为Sheet2
    xlsx.write(3, 4, "插入图表,引用Sheet1数据");
    Chart* barChart8 = xlsx.insertChart(3, 3, QSize(300, 300));  // 插入图表
    barChart8->setChartType(Chart::CT_BarChart);
    barChart8->setChartLegend(Chart::Right);
    barChart8->setChartTitle("Test8");
    barChart8->addSeries(CellRange(1, 1, 3, 10), xlsx.sheet("Sheet1"));   // 添加数据系列范围,并指定为Sheet1中的数据

    if(xlsx.saveAs(EXCEL_NAME))                             // 如果文件已经存在则覆盖
    {
        qInfo() << "保存成功!";
    }
    else
    {
        qWarning() << "保存失败!";
    }

插入图表Sheet,并绘制一个柱状图:

Document xlsx;
    for(int i = 1; i < 10; i++)
    {
        xlsx.write(i, 1, i * i);         // 在Sheet1中写入1列数据
    }

    xlsx.addSheet("Chart1", AbstractSheet::ST_ChartSheet);               // 插入一个名称为【Chart1】,类型为【图表】的Sheet
    Chartsheet* sheet = static_cast<Chartsheet*>(xlsx.currentSheet());   // 获取当前工作表,并将类型转换为Chartsheet*
    Chart* barChart = sheet->chart();           // 图表Sheet中会默认内置一个Chart,从这一步开始就和正常操作图表一样了
    barChart->setChartType(Chart::CT_BarChart); // 设置图表类型位柱状图
    barChart->addSeries(CellRange("A1:A9"), xlsx.sheet("Sheet1")); // 添加数据系列,数据位于Sheet1中的A1-A9

    if(xlsx.saveAs(EXCEL_NAME))                             // 如果文件已经存在则覆盖
    {
        qInfo() << "保存成功!";
    }
    else
    {
        qWarning() << "保存失败!";
    }

18、在当前Sheet指定位置插入图片

Document xlsx;

    QImage image1("://image/C++.PNG");
    QImage image2("://image/Qt.PNG");

    qDebug() << "插入图片:"<<xlsx.insertImage(3, 3, image1);  // 在3行3列单元格右下角位置插入图片
    qDebug() << "插入图片:"<<xlsx.insertImage(23, 3, image2);  // 在23行3列单元格右下角位置插入图片

    if(xlsx.saveAs(EXCEL_NAME))    // 如果文件已经存在则覆盖
    {
        qInfo() << "Excel保存成功!";
    }
    else
    {
        qWarning() << "Excel保存失败!";
    }

19、获取当前Sheet中图片个数

Document xlsx(EXCEL_NAME);
    if(!xlsx.load())
    {
        return;
    }

    uint count = xlsx.getImageCount();       // 查询当前Sheet中图片数量

20、通过索引方式和行列号方式读取当前Sheet中的图片

Document xlsx(EXCEL_NAME);

    QImage image;
    bool ret = xlsx.getImage(1, image);       // 读取当前Sheet中第1张图片(注意:索引是从1开始,而不是从0开始)

    bool ret1 = xlsx.getImage(23, 3, image);       // 读取当前Sheet中第2张图片

21、演示三种方式的单元格合并

1、通过【单元格引用】直接设置单元格合并;
2、通过【行列号】设置单元格合并;
3、在设置单元格合并时可以设置单元格【格式】,如文本居中对齐

Document xlsx;

    // 在Excel中写入三组数据
    xlsx.write("B3", "hello");
    xlsx.write("C3", "123");
    xlsx.write("B8", 123456);
    xlsx.write("E8", "北风卷地白草折,胡天八月即飞雪");

    xlsx.mergeCells("B3:F6");                  // 可以通过【单元格引用】直接设置单元格合并(注意,有数据的单元格应该时第一个位置)
    xlsx.mergeCells(CellRange(8, 2, 20, 3));   // 通过【行列号】设置单元格合并

    Format format;
    format.setHorizontalAlignment(Format::AlignHCenter);  // 水平居中
    format.setVerticalAlignment(Format::AlignVCenter);    // 垂直居中
    xlsx.mergeCells("E8:F20", format);                    // 在设置单元格合并时可以设置单元格【格式】,如文本居中对齐

    if(xlsx.saveAs(EXCEL_NAME))    // 如果文件已经存在则覆盖
    {
        qInfo() << "Excel保存成功!";
    }
    else
    {
        qWarning() << "Excel保存失败!";
    }

22、取消合并单元格

Document xlsx(EXCEL_NAME);
    if(!xlsx.load())
    {
        return;
    }

    xlsx.unmergeCells("B3:F6");   // 这里取消合并的范围【B3:F6】必须和之前合并单元格的【范围相同】,否则取消合并失败
    if(xlsx.save())
    {
        qInfo() << "Excel保存成功!";
    }
    else
    {
        qWarning() << "Excel保存失败!";
    }

23、在不修改其它内容情况下设置单元格水平对齐

Document xlsx(EXCEL_NAME);
    if(!xlsx.load())
    {
        return;
    }
    int index = 2;
    Format format = xlsx.cellAt(8, 2)->format();                        // 获取单元格原有格式
    format.setHorizontalAlignment(Format::HorizontalAlignment(index));  // 设置单元格水平对齐格式
    xlsx.write(8, 2, xlsx.read(8, 2), format);                          // 将单元格原有内容、格式写入原来位置

    if(xlsx.save())
    {
        qInfo() << "Excel保存成功!";
    }
    else
    {
        qWarning() << "Excel保存失败!";
    }

24、在不修改其它内容情况下设置单元格垂直对齐

Document xlsx(EXCEL_NAME);
    if(!xlsx.load())
    {
        return;
    }
    int index = 2;
    Format format = xlsx.cellAt(8, 2)->format();                        // 获取单元格原有格式
    format.setVerticalAlignment(Format::VerticalAlignment(index));      // 设置单元格垂直对齐格式
    xlsx.write(8, 2, xlsx.read(8, 2), format);                          // 将单元格原有内容、格式写入原来位置

    if(xlsx.save())
    {
        qInfo() << "Excel保存成功!";
    }
    else
    {
        qWarning() << "Excel保存失败!";
    }

25、通过索引号设置数字格式

Document xlsx;

    Format format;
    for(int i = 1; i < 100; i++)
    {
        format.setNumberFormatIndex(i);
        xlsx.write(i, 1, 1234, format);
        xlsx.write(i, 3, 1234.321, format);
        qDebug() << xlsx.cellAt(i, 1)->format().numberFormatIndex();  // 获取当前单元格的数字格式
    }

    if(xlsx.saveAs(EXCEL_NAME))
    {
        qInfo() << "Excel保存成功!";
    }
    else
    {
        qWarning() << "Excel保存失败!";
    }

26、设置自定义数字格式

Document xlsx;

    Format format;
    format.setNumberFormat("# ?/?");
    xlsx.write(1, 1, 1234.321, format);
    format.setNumberFormat("[Red][<=100];[Green][>100]");
    xlsx.write(2, 1, 14.321, format);

    if(xlsx.saveAs(EXCEL_NAME))
    {
        qInfo() << "Excel保存成功!";
    }
    else
    {
        qWarning() << "Excel保存失败!";
    }

27、设置字体样式

Document xlsx;

    xlsx.write(1, 1, "默认样式");

    // 设置字体大小
    Format format;
    format.setFontSize(15);
    xlsx.write(1, 2, "字体大小15", format);
    qDebug() << xlsx.cellAt(1, 2)->format().fontSize();  // 获取当前单元格的字体大小

    // 设置字体斜体
    Format format1;
    format1.setFontItalic(true);
    xlsx.write(1, 3, "斜体", format1);
    qDebug() << xlsx.cellAt(1, 3)->format().fontItalic();  // 获取当前单元格的字体是否为 斜体

    // 设置字体删除线
    Format format2;
    format2.setFontStrikeOut(true);
    xlsx.write(1, 4, "删除线", format2);
    qDebug() << xlsx.cellAt(1, 4)->format().fontStrikeOut();  // 获取当前单元格的字体是否有 删除线

    // 设置字体颜色
    Format format3;
    format3.setFontColor(Qt::red);
    xlsx.write(1, 5, "字体颜色", format3);
    qDebug() << xlsx.cellAt(1, 5)->format().fontColor();  // 获取当前单元格的字体颜色

    // 设置字体加粗
    Format format4;
    format4.setFontBold(true);
    xlsx.write(1, 6, "字体加粗", format4);
    qDebug() << xlsx.cellAt(1, 6)->format().fontBold();  // 获取当前单元格的字体是否加粗

    // 设置字体特殊格式(上、下标)
    Format format5;
    format5.setFontScript(Format::FontScriptSub);   // 设置下标
    xlsx.write(1, 7, "字体下标", format5);
    format5.setFontScript(Format::FontScriptSuper); // 设置上标
    xlsx.write(1, 8, "字体上标", format5);
    qDebug() << xlsx.cellAt(1, 7)->format().fontScript();  // 获取当前单元格的字体的特殊格式

    // 设置下划线
    Format format6;
    format6.setFontUnderline(Format::FontUnderlineNone);
    xlsx.write(1, 9, "无下划线", format6);
    format6.setFontUnderline(Format::FontUnderlineSingle);
    xlsx.write(1, 10, "单下划线", format6);
    format6.setFontUnderline(Format::FontUnderlineDouble);
    xlsx.write(1, 11, "双下划线", format6);
    format6.setFontUnderline(Format::FontUnderlineSingleAccounting);
    xlsx.write(1, 12, "会计用单下划线", format6);
    format6.setFontUnderline(Format::FontUnderlineDoubleAccounting);
    xlsx.write(1, 13, "会计用双下划线", format6);
    qDebug() << xlsx.cellAt(1, 9)->format().fontUnderline();  // 获取当前单元格文本下划线格式

    // 设置字体轮廓
    Format format7;
    format7.setFontOutline(true);
    xlsx.write(1, 14, "字体轮廓", format7);
    qDebug() << xlsx.cellAt(1, 14)->format().fontOutline();  // 获取当前单元格是否打开字体轮廓

    // 设置字体类型
    Format format8;
    format8.setFontName("黑体");
    xlsx.write(1, 15, "字体类型", format8);
    qDebug() << xlsx.cellAt(1, 15)->format().fontName();  // 获取当前单元格字体类型

    if(xlsx.saveAs(EXCEL_NAME))
    {
        qInfo() << "Excel保存成功!";
    }
    else
    {
        qWarning() << "Excel保存失败!";
    }

28、设置列宽或者行高

函数原型:
bool Document::setColumnWidth(int column, double width)
示例:
xlsx.setColumnWidth(第几列, 列宽); 

函数原型:
bool Document::setColumnWidth(int colFirst, int colLast, double width)
示例:
xlsx.setColumnWidth(开始列, 结束列, 列宽);

QXlsx::Document xlsx;
xlsx.setRowHeight(第几行, 行高);
xlsx.setRowHeight(第几行, 结束行, 行高);

29、设置单元格样式

QXlsx::Format titleFormat;

1、设置垂直对齐格式

函数原型:
void Format::setVerticalAlignment(VerticalAlignment align)
示例:
titleFormat.setVerticalAlignment(Format::VerticalAlignment::AlignVCenter);//格式垂直居中
垂直对齐各种样式如下:
	enum VerticalAlignment {
		AlignTop, 		//顶端对齐
		AlignVCenter,	//垂直居中
		AlignBottom,	//底部对齐
		AlignVJustify,	//两端对齐
		AlignVDistributed
	};

2、设置水平对齐格式

示例:
titleFormat.setHorizontalAlignment(Format::VerticalAlignment::AlignLeft);
水平对齐各种样式如下:
    enum HorizontalAlignment {
        AlignHGeneral,
        AlignLeft,	//左对齐
        AlignHCenter,//水平居中对齐
        AlignRight,	//右对齐
        AlignHFill,
        AlignHJustify,
        AlignHMerge,
        AlignHDistributed
    };

3、设置边框样式,自动换行等

未设置的效果:
在这里插入图片描述
自动换行

headerFormat.setTextWarp(true);//自动换行

设置后:
在这里插入图片描述

边框样式有如下:

enum BorderStyle {
        BorderNone,
        BorderThin,
        BorderMedium,
        BorderDashed,
        BorderDotted,
        BorderThick,
        BorderDouble,
        BorderHair,
        BorderMediumDashed,
        BorderDashDot,
        BorderMediumDashDot,
        BorderDashDotDot,
        BorderMediumDashDotDot,
        BorderSlantDashDot
    };
QXlsx::Format format;/*设置该单元的样式*/
/*单元格边框样式*/
format.setBorderStyle(QXlsx::Format::BorderMedium);//中等线条边框
format.setBorderStyle(QXlsx::Format::BorderDashed);//虚线边框
format.setBorderStyle(QXlsx::Format::BorderDotted);//打点边框
format.setBorderStyle(QXlsx::Format::BorderThick);//粗边框
format.setBorderStyle(QXlsx::Format::BorderThin);//细边框
format.setBorderStyle(QXlsx::Format::BorderDouble);//双重边框
format.setBorderStyle(QXlsx::Format::BorderDashDot);//点线间隔边框
/*单元格背景颜色*/
format.setPatternBackgroundColor(QColor("#00B050"));
format.setPatternForegroundColor(Qt::red);

单元格不同方向的边框及颜色:

QXlsx::Format format;/*设置该单元的样式*/
format.setTopBorderStyle(QXlsx::Format::BorderThin);
format.setBottomBorderStyle(QXlsx::Format::BorderThin);
format.setLeftBorderStyle(QXlsx::Format::BorderThin);
format.setRightBorderStyle(QXlsx::Format::BorderThin);
format.diagonalBorderStyle(QXlsx::Format::BorderThin);

format.setBorderColor(QColor("#000000"));//边框颜色
format.setLeftBorderColor(QColor("#000000"));//边框颜色
format.setRightBorderColor(QColor("#000000"));//边框颜色
format.setTopBorderColor(QColor("#000000"));//边框颜色
format.setBottomBorderColor(QColor("#000000"));//边框颜色
format.setDiagonalBorderColor(QColor("#000000"));//边框颜色

参考:
https://blog.csdn.net/qq_43627907/category_11756312.html
https://blog.csdn.net/qq_44667165/article/details/128385273
http://www.taodudu.cc/news/show-4548354.html?action=onClick

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/364063.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

消息中间件之RocketMQ源码分析(四)

消费者的Rebalance机制 客户端是通过Rebalance服务做到高可靠的。当发生Broker掉线、消费者实例掉线、 Topic扩容等各种突发情况时&#xff0c;消费者组中的消费者实例是怎么重平衡的&#xff0c;以支持全部队列的正常消费的? Rebalance服务的类图 RebalanceImpl的核心属性 …

CHS_06.2.3.4_2+用信号量实现进程互斥、同步、前驱关系

CHS_06.2.3.4_2用信号量实现进程互斥、同步、前驱关系 知识总览信号量机制实现进程互斥信号量机制实现进程同步信号量机制实现前驱关系 知识回顾 各位同学 大家好 在这个小节中 我们要学习怎么用信号量机制来实现进程的同步互制关系 知识总览 那么 我们之前学习了互斥的几种软…

【C++杂货铺】详解类和对象 [下]

个人博客&#xff1a;代码菌-CSDN博客 专栏&#xff1a;C杂货铺_代码菌的博客-CSDN博客 目录 &#x1f308;前言&#x1f308; &#x1f4c1; 初始化列表&#xff08;灰常重要&#xff09; &#x1f4c2; 引入 &#x1f4c2; 概念 &#x1f4c2; 特性 &#x1f4c1; 拓展构…

OG Trade在ZKX揭幕:一家基于Starknet的游戏化永续合约交易所

ZKX的 OG Trade通过内置游戏化和30分钟交易竞赛&#xff0c;为所有交易者创造机会&#xff0c;革新了永续合约交易模式。 2024年1月30日 — ZKX宣布推出OG Trade&#xff0c;这是一家基于Starknet的游戏化永续合约交易所&#xff0c;旨在满足短期交易者、高水平交易者和波段交易…

021 while循环详解

什么时while循环 int i 0; // 循环输出i&#xff0c;大于100时结束 while(i < 100){System.out.println(i);i; } int i 0; int sum 0; // 计算1-100的和&#xff0c;输出 while(i < 100){sum i;i; } System.out.println(sum); 什么是死循环 循环没有停止下来的条件…

Vue3嵌套ref小细节,自我解惑

前言&#xff1a; 作者在学习时&#xff0c;遇到代码如下&#xff1a; import { ref,watch } from vue const state ref({count:0}) const addState ()>{state.value.count } 对于方法中对对象中count的理解存在偏差 问题及解决&#xff1a; 误解&#xff1a; 认为是…

面对近期行情大起大落的伦敦银需要关注什么?

近期经常有听到投资者抱怨说&#xff0c;伦敦银价格没有明显趋势&#xff0c;很难做。确实&#xff0c;我们从日线图看&#xff0c;金价处于一个比较宽幅的横盘区间当中&#xff0c;近期的行情也是大涨大跌。投资者认为&#xff0c;面对大起大落的行情无从下手。下面我们就来讨…

会话管理技术

会话管理 会话管理是跟踪用户跨网页活动的过程。以在线购物商场为例。用户可以选择产品并将其添加到购物车中。用户转到其他页面时,购物车中仍然保留详细信息,以便用户查看购物车中的物品并下订单。 会话跟踪也可用于跟踪用户的偏好。例如,如果用户选择了多本小说,则向用…

内网安全:RDP WinRS WinRM SPN Kerberos 横向移动

目录 WinRM协议 RDP协议 域横向移动&#xff1a;RDP协议 RDP协议利用 一. 探针服务 二. 获取NTML Hash 明文密码 三. 连接执行 域横向移动&#xff1a;WinRM WinRS WinRM协议、WinRS命令利用 一. cs 内置端口扫描5985 二. 连接执行 三. 上线CS 四. CS插件横向移动…

基于springboot+vue的阿博图书馆管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

Springboot项目基础配置:小白也能快速上手!

推荐文章 给软件行业带来了春天——揭秘Spring究竟是何方神圣&#xff08;一&#xff09; 给软件行业带来了春天——揭秘Spring究竟是何方神圣&#xff08;二&#xff09; 给软件行业带来了春天——揭秘Spring究竟是何方神圣&#xff08;三&#xff09; 给软件行业带来了春天—…

vue-cli项目运行流程介绍

一、前言 ​ 本文介绍 vue-cli搭建的项目运行流程&#xff0c;基于已经搭建好的基础项目。关于 vue-cli 构建项目的详细流程&#xff0c;可参考博文&#xff1a;使用vue脚手架构建项目 二、main.js 项目运行 会加载入口文件 main.js /* html文件中&#xff0c;通过script …

CTF盲水印工具:Blind-WaterMark安装

工具下载地址&#xff1a;GitCode - 开发者的代码家园 下载完毕后&#xff0c;只留这些东西就行 接下来需要安装两个依赖&#xff1a; opencv、matplotlib 直接pip install安装的话&#xff0c;工具使用会报错 所以需要到网站里挑选适合的版本进行安装 下载地址&#xff1…

DrissionPage多线程实践

DrissionPage多线程实践 背景&#xff1a;项目中需要抓取部分平台的数据&#xff0c;因为涉及到登录&#xff0c;且暂未实现接口登录。所以采用selenium登录后获取cookie传给requests的方式来实现。后了解到DrissionPage国产开源库&#xff0c;等于是把selenium和requests结合起…

部署YUM仓库服务

一、yum仓库 1. yum简介 yum是一个基于RPM包&#xff08;是Red-Hat Package Manager红帽软件包管理器的缩写&#xff09;构建的软件更新机制&#xff0c;能够自动解决软件包之间的依赖关系。 为什么会有依赖关系的发生 因为linux本身就是以系统简洁为自身优势&#xff0c;所以…

大数据信用报告应该去哪里查询比较好呢?

对于个人而言&#xff0c;大数据信用报告也变得越来越重要。那么&#xff0c;大数据信用报告应该去哪里查询呢?本文将为您详细介绍征信和大数据的区别&#xff0c;并推荐一个可靠的大数据平台。 首先&#xff0c;我们需要了解征信和大数据的区别 征信报告 依法采集、整理、保存…

day13_oop_抽象类_接口

今日内容 零、 复习昨日 一、作业 二、抽象 三、接口 零、 复习昨日 final的作用 最终的,修饰的类,属性,方法不能改变类不能继承,属性不能改变(常量),方法不能重写 static修饰方法的特点 修饰的属性方法在内存只有一份随着类加载而初始化不要new,可以通过类名直接调用被该类的所…

异或运算实现加密解密

异或运算符^&#xff0c;相同为0&#xff0c;不同为1&#xff08;同0非1&#xff09; 由异或运算法则可知&#xff1a;a ^ a 0&#xff0c;a ^ 0 a 如果c a ^ b&#xff0c;那么a b ^ c&#xff0c;即a ^ b ^ b a&#xff0c;^ 的逆运算仍然是 ^ 利用异或运算的性质&am…

LabVIEW船舶自动识别系统

在现代航海领域&#xff0c;安全高效的船舶自动识别系统对于保障航行安全和提高船舶管理效率非常重要。介绍了利用LabVIEW软件开发的一个船舶自动识别系统&#xff0c;该系统通过先进的数据采集和信号处理技术&#xff0c;显著提升了传统自动识别系统的性能。 这个船舶自动识别…

IAR编译和调试CMS32L051

0 Preface/Foreword 0.1 参考文档 中微半导体BAT系列单片机学习笔记_V1.1.pdf 1 配置方法 1.1 编译工具链添加 CMS对于IAR工具&#xff0c;有一个插件文件&#xff0c;用于安装对应的CMS系列芯片。 工具名称&#xff1a;iar_plug20210926.7z 按照完成之后&#xff0c;可…