Qt操作Excel

1. 库的下载与安装

由于xlsxwriter库是跨平台的,支持读写操作的,所以我选择该第三方库来操作excel
该库的镜像地址如下:
https://gitcode.com/gh_mirrors/qt/QtXlsxWriter/overview?utm_source=csdn_github_accelerator
克隆命令为:
git clone https://gitcode.com/gh_mirrors/qt/QtXlsxWriter.git
克隆完成后有两种使用方式,我只记录一种:往工程里导pri的方式,这种方式使用简单粗暴,但是需要每一个工程都放进去。

1.1 建文件夹

第一步:在项目的目录下新建一个xlsxwriter的文件夹,在其内部再新建一个src的子文件夹;
第二步:将克隆下来的src文件夹里的内容复制到上一步新建的文件夹中;
第三步:在工程文件pro文件中加入pri文件,即
include(XlsxWriter/src/xlsx/qtxlsx.pri)
工程就变成了这样目录

就可以在其他文件引用相应的头文件

2. Qt具体操作Excel方式

直接把代码放过来一行一行注释自己看

#include "dailyreport.h"
#include "ui_dailyreport.h"
#include "xlsxdocument.h"
#include "xlsxformat.h"
#include "readfile.h"

void DailyReport::on_pushButton_chaxun_3_clicked()
{
    selectedMonth = ui->dateEdit->date(); // 假设你的界面上有一个日期选择器
    generateDailyReport(selectedMonth);
}

void DailyReport::generateDailyReport(const QDate &daily)
{
    SQLHelper sqlhelper;
    sqlhelper.openDataBase();
    QSqlQuery sqlquery;
    QString queryString = QString("SELECT DateTime, liuliang FROM shuiwei WHERE DATE(DateTime) = '%1'").arg(daily.toString("yyyy-MM-dd"));
    if (!sqlquery.exec(queryString))
    {
        QMessageBox::critical(this,"错误","数据查询失败");
        return;
    }

    QMap<QDate, QMap<int, QList<float>>> hourlyData;
    while (sqlquery.next())
    {
        QDateTime datetime = sqlquery.value("DateTime").toDateTime();
        float liuliang = sqlquery.value("liuliang").toFloat();
        QDate date = datetime.date();    // 获取日期
//        qDebug() << date;
        int hour = datetime.time().hour();    // 获取小时
//        qDebug() << hour;
        hourlyData[date][hour].append(liuliang);
    }
//    qDebug() << hourlyData;

    displayHourlyDataInTable(hourlyData);
}

void DailyReport::displayHourlyDataInTable(const QMap<QDate, QMap<int, QList<float> > > &hourlyData)
{
    model->clear();
    // 设置表头
    QStringList horizontalHeader;
    horizontalHeader << "序号" << "监测日期" << "监测时间" << "实测数据(m³/s)" << "累计流量(m³)" << "生态流量异常原因";
    model->setHorizontalHeaderLabels(horizontalHeader);
    // 向模型填充数据
    int row = 0;
    for (auto dayIt = hourlyData.begin(); dayIt != hourlyData.end(); dayIt++, row++)
    {
        const QDate &date = dayIt.key();    // 获取外层键   也就是日期  QDate("2024-09-03")
        const QMap<int, QList<float>> &hoursData = dayIt.value();    // 获取值 QMap(0, (8.149))
//        QStandardItem *dateItem = new QStandardItem(date.toString("yyyy-MM-dd"));

        for (int hour = 0; hour < 24; hour++)
        {
            QStandardItem *timeItem = new QStandardItem(QString("%1:00").arg(hour,2,10,QChar('0')));
            QStandardItem *hours = new QStandardItem(QString::number(hour + 1));
            QStandardItem *dateItem = new QStandardItem(date.toString("yyyy-MM-dd"));
            model->setItem(hour,0, hours);    // 强转
            model->setItem(hour, 1, dateItem); // 第一列  日期
            model->setItem(hour,2,timeItem);
            timeItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
            hours->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
            dateItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
            if (hoursData.contains(hour))
            {
                const float &data = hoursData[hour][0];
                QString data_string = QString::number(data,'f',4);
                QStandardItem *hourlyData = new QStandardItem(data_string);
                model->setItem(hour,3,hourlyData);
                hourlyData->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
                const float &data_total = data_string.toFloat() * 3600;
                QStandardItem *hourlyData_total = new QStandardItem(QString::number(data_total,'f',2));
                model->setItem(hour,4,hourlyData_total);
                hourlyData_total->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
            }
            else
            {
                QStandardItem hourItem("N/A");
                model->setItem(row, hour + 1, &hourItem);
            }
        }
    }
}

void DailyReport::initTableView()
{
    ui->tableView->setModel(model);
    ui->tableView->resizeColumnsToContents();
    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);     //设置表格的单元为只读属性,即不能编辑
    ui->tableView->verticalHeader()->hide();      //隐藏行头
    ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);  //设置列的宽度
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);      // 设置表格的选择行为为选择整行  而不是单个单元格
}

void DailyReport::exportToXls(QStandardItemModel *model, const QString &fileName, const QString &powerName, const QString &exportDate)
{
    // 创建excel表对象
    QXlsx::Document xls;
    // 创建标题格式的对象
    QXlsx::Format format_title;
    // 设置水平居中
    format_title.setHorizontalAlignment(QXlsx::Format::AlignHCenter);
    // 设置垂直居中
    format_title.setVerticalAlignment(QXlsx::Format::AlignVCenter);
    
    // 设置字体大小
    format_title.setFontSize(36);
    // 设置字体加粗
    format_title.setFontBold(true);
    
    // 写excel
    xls.write("A1","生态流量日报表");    
    // 合并单元格
    xls.mergeCells("A1:F7",format_title);    
    
    // 创建电站名称格式对象
    QXlsx::Format format_powerName;

    // 设置水平居中
    format_powerName.setHorizontalAlignment(QXlsx::Format::AlignHCenter);
    // 设置垂直居中
    format_powerName.setVerticalAlignment(QXlsx::Format::AlignVCenter);
    // 设置字体大小
    format_powerName.setFontSize(36);
    // 设置边框
    format_powerName.setBorderStyle(QXlsx::Format::BorderStyle::BorderThin);
    // 写入数据
	xls.write("A8",QString("%1(%2)").arg(powerName).arg(exportDate));
    // 合并单元格  A8:F14
	xls.mergeCells("A8:F14",format_powerName);
	
	// 创建表头的格式对象
    QXlsx::Format format_TableTitle;
    // 设置垂直居中
	format_TableTitle.setVerticalAlignment(QXlsx::Format::AlignVCenter);
    // 设置水平居中
	format_TableTitle.setHorizontalAlignment(QXlsx::Format::AlignHCenter);
    
	// 设置字体大小
	format_TableTitle.setFontSize(22);
    // 设置字体加粗
	format_TableTitle.setFontBold(true);
    // 设置行高  第几行 行高 注意这里用的是xls对象
	xls.setRowHeight(15,47.4);
	// 设置边框样式
	format_TableTitle.setBorderStyle(QXlsx::Format::BorderStyle::BorderThin);
    // 设置列宽 第几列 宽度
	xls.setColumnWidth(1,11.33);
    xls.setColumnWidth(2,25.22);
    xls.setColumnWidth(3,21.00);
    xls.setColumnWidth(4,34.78);
    xls.setColumnWidth(5,29.33);
    xls.setColumnWidth(6,54.33);
    // 写入数据 第几行 第几列 内容  格式
	xls.write(15,1,"序号",format_TableTitle);
    xls.write(15,2,"监测日期",format_TableTitle);
    xls.write(15,3,"监测时间",format_TableTitle);
    xls.write(15,4,"实测流量(m³/s)",format_TableTitle);
    xls.write(15,5,"累计流量(m³)",format_TableTitle);
    xls.write(15,6,"生态流量异常原因",format_TableTitle);
	// 创建表格内容的单元格格式
    QXlsx::Format format_Table;
    // 设置字体大小
	format_Table.setFontSize(22);
    // 设置垂直居中
	format_Table.setVerticalAlignment(QXlsx::Format::AlignVCenter);
    // 设置水平居中
	format_Table.setHorizontalAlignment(QXlsx::Format::AlignHCenter);
    // 设置边框格式
	format_Table.setBorderStyle(QXlsx::Format::BorderStyle::BorderThin);
    // 循环遍历模型中的数据
	for (int row = 0; row < model->rowCount(); row++)
    {
        for (int col = 0; col < model->columnCount(); col++)
        {
			// 获取具体格子的数据
            QModelIndex index = model->index(row, col);
			//  转换格式 
			QString data = index.data(Qt::DisplayRole).toString();
            // 向excel写入数据
			xls.write(row+16,col+1,data,format_Table);
            // 调整行高
			xls.setRowHeight(row + 16, 47.4);
        }
    }
	
    QXlsx::Format format_bottom;
    format_bottom.setHorizontalAlignment(QXlsx::Format::AlignLeft);
    format_bottom.setVerticalAlignment(QXlsx::Format::AlignVCenter);
    format_bottom.setFontSize(22);
    xls.write("A40","    部门负责人:                                            值长:                                             值班人员:                ",format_bottom);
    xls.mergeCells("A40:F47");
    
	// 保存文件
	xls.saveAs(fileName + ".xlsx");
}


void DailyReport::on_save_clicked()
{

    if (model->rowCount() == 0)
    {
        QMessageBox::critical(this,"错误","没有要导出的数据");
        return;
    }

    if (!model)
    {
        QMessageBox::critical(this,"错误","数据模型未准备好");
        return;
    }

    // 提示用户选择保存位置和文件名
    QString fileName = QFileDialog::getSaveFileName(this,tr("Save File"),QDir::homePath(),tr("xls Files (*.xls);;All Files (*)"));
    if (fileName.isEmpty())
    {
        return;
    }
     ReadFile readFile;
    // 调用导出函数保存数据到CSV文件
//    exportToCSV(model, fileName);
    exportToXls(model,fileName,readFile.powerName, selectedMonth.toString("yyyy-MM-dd"));
}

最终效果

3. 好的参考网站

这个博客给出了官方的例子 包括生成图像
https://blog.csdn.net/u014779536/article/details/111769792