Bootstrap

Qt WORD/PDF(五)使用Json一键填充Word表格


关于QT Widget 其它文章请点击这里:     QT Widget

国际站点 GitHub:     https://github.com/chenchuhan
国内站点 Gitee :      https://gitee.com/chuck_chee

姊妹篇:     

《Qt WORD/PDF(一)使用 QtPdfium库实现 PDF 操作》

《Qt WORD/PDF(二)使用 QtPdfium库实现 PDF 预览、打印等》

《Qt WORD/PDF(三)使用 QAxObject 对 Word 替换(QML)》

《Qt WORD/PDF(四)使用 QAxObject 对 Word 替换(QWidget)》

《Qt WORD/PDF(五)使用Json一键填充Word表格》》


一、前言

QAxObject 是 Qt 提供的一个类,它用于与 COM(Component Object Model)对象进行交互。COM 是一种微软的技术,广泛用于各种应用程序之间的通信,尤其在 Windows 平台上,很多软件和系统组件都是基于 COM 构建的。QAxObject 类提供了一个 Qt 风格的接口,简化了与这些 COM 对象的交互。

此Demo主要功能是利用 Qt 和 Microsoft Word 的 COM 接口实现自动化操作,填充和高亮 Word 文档中的表格内容。

它可以应用于自动化报告生成,例如在教育系统中自动生成学生成绩单,或在企业中生成财务报表和考勤记录。模板文档与 JSON 数据源结合,减少了人工操作的工作量。

二、演示

Json 文件导入一键填充/替换模板表格,根据Json填充单元格内容,候选单元格背景高亮等:

请添加图片描述

三、部分代码

//表格填充方案
void WordTableOperation::fillWordTable()
{

    QString jsonPath =      _jsonFile;
    QString templatePath =  _templateFile;
    QString outputPath =    _reportFile;

    qDebug() << "jsonPath:" << jsonPath;
    qDebug() << "templatePath:" << templatePath;
    qDebug() << "outputPath:" << outputPath;


    if (jsonPath.isEmpty() || templatePath.isEmpty() || outputPath.isEmpty()) {
        qDebug() << "请填写模板路径和输出路径!";
        return;
    }


    QFile file(jsonPath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qWarning() << "Failed to open JSON file!";
        return;
    }

    wordApp = std::make_unique<QAxObject>("Word.Application");

    documents = wordApp->querySubObject("Documents");
    document = documents->querySubObject("Open(const QString&)", templatePath);
    if (!document) {
        qDebug() << "Failed to open document.";
        return  ;
    }

    QAxObject *tables = document->querySubObject("Tables");
    QAxObject *table = tables->querySubObject("Item(int)", 1);

    QAxObject* cells = table->querySubObject("Range")->querySubObject("Cells");
    if (!cells) {
        qDebug() << "无法获取表格的 Cells。";
        return;
    }
    int cellCount = cells->dynamicCall("Count()").toInt();
    qDebug() << "表格总单元格数量:" << cellCount;

    ///Json
    QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
    file.close();
    QJsonObject rootObj = doc.object();
    QJsonObject mainCard = rootObj.value("成绩表").toObject();

    //3~7
    _setCellValueint(3, cells, mainCard["姓名"].toString());
    _setCellValueint(5, cells, mainCard["年级"].toString());
    _setCellValueint(7, cells, mainCard["性别"].toString());

    //10~25
    QJsonObject grade = mainCard.value("分数").toObject();
    _setCellValueint(10, cells, grade.value("语文").toString());
    _setCellValueint(12, cells, grade.value("数学").toString());
    _setCellValueint(14, cells, grade.value("英语").toString());

    _highlightCells(16,20, cells, mainCard, "级别");

    document->dynamicCall("SaveAs(const QString&)", outputPath); //另存为word

    qDebug() << "word 另存为:" << outputPath;

    document->dynamicCall("Close()");
    wordApp->dynamicCall("Quit()");

}


// 设置单元格内容的封装函数
void WordTableOperation::_setCellValueint(int cellIndex, QAxObject* cells,  const QString& value) {

    // 获取目标单元格
    QAxObject* cell = cells->querySubObject("Item(int)", cellIndex);
    if (!cell) {
        qWarning() << "无法获取单元格,索引:" << cellIndex;
        cells->deleteLater();
        return;
    }

    // 获取 Range 并设置文本
    QAxObject* range = cell->querySubObject("Range");
    range->setProperty("Text", value);

}

void WordTableOperation::_highlightCells(int start, int end, QAxObject* cells, const QJsonObject& jsonObject, const QString& name) {

    QString targetValue = jsonObject.value(name).toString();

    for (int i = start; i <= end; ++i) {
        QAxObject* cell = cells->querySubObject("Item(int)", i);
        if (!cell) continue;

        QAxObject* range = cell->querySubObject("Range");
        if (!range) continue;

        QString cellText = range->property("Text").toString().simplified();
        QAxObject* shading = cell->querySubObject("Shading");

        //只要包含就行
        if (cellText.contains(targetValue)) {
            if (shading) {
                shading->setProperty("BackgroundPatternColor", QVariant(16753920));
            }
        } else {
            if (shading) {
                shading->setProperty("BackgroundPatternColor", QVariant(16777215)); // White color QVariant(QColor(Qt::white).rgb()));
            }
        }
    }
}

Json文件

{
  "成绩表": {
    "姓名": "小明",
    "年级": "四年级",
    "性别": "男",
    "分数": {
      "语文": "92",
      "数学": "98",
      "英语": "91"
    },
    "级别": "优秀"
  }
}
 

四、简要分析

 
获取表格和单元格信息:

QAxObject* tables = document->querySubObject("Tables");
QAxObject* table = tables->querySubObject("Item(int)", 1);
QAxObject* cells = table->querySubObject("Range")->querySubObject("Cells");
int cellCount = cells->dynamicCall("Count()").toInt();
    qDebug() << "表格总单元格数量:" << cellCount;

注意因为表格中行和列是不规则的,所以通过行列获取单元格信息,不如直接获取每一个单元格更合适

int rowCount = table->querySubObject("Rows")->dynamicCall("Count()").toInt();
int colCount = table->querySubObject("Columns")->dynamicCall("Count()").toInt();

填充单元格数据:

void WordTableOperation::_setCellValueint(int cellIndex, QAxObject* cells,  const QString& value) {
    // 获取目标单元格
    QAxObject* cell = cells->querySubObject("Item(int)", cellIndex);
    if (!cell) {
        qWarning() << "无法获取单元格,索引:" << cellIndex;
        cells->deleteLater();
        return;
    }
    QAxObject* range = cell->querySubObject("Range");
    range->setProperty("Text", value);
}

单元格背景高亮:

void WordTableOperation::_highlightCells(int start, int end, QAxObject* cells, const QJsonObject& jsonObject, const QString& name) {
    QString targetValue = jsonObject.value(name).toString();
    for (int i = start; i <= end; ++i) {
        QAxObject* cell = cells->querySubObject("Item(int)", i);
        if (!cell) continue;

        QAxObject* range = cell->querySubObject("Range");
        if (!range) continue;

        QString cellText = range->property("Text").toString().simplified();
        QAxObject* shading = cell->querySubObject("Shading");

        //只要包含就行
        if (cellText.contains(targetValue)) {
            if (shading) {
                shading->setProperty("BackgroundPatternColor", QVariant(16753920));
            }
        } else {
            if (shading) {
                shading->setProperty("BackgroundPatternColor", QVariant(16777215)); 
            }
        }
    }
}

五、功能特点:

  1. 使用 QAxObject 实现了与 Word 的 COM 接口的交互,允许直接操作 Word 文档中的内容;
  2. Json 文件导入一键填充/替换模板表格,根据Json填充单元格内容,候选单元格背景高亮等;
  3. 各个路径可设置,合理性判定等。

六、可优化:

  1. 后续可使用 QScopedPointer 自动管理 QAxObject 的生命周期,避免内存泄漏;
  2. 可增加对失败情况的详细日志记录(例如,单元格索引等);
  3. 路径可通过 Setting 保存在内容中;
  4. 增加预览功能,可结合前文PDF的预览。

关于QGC地面站其它文章请点击这里:     QT Widget

;