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填充单元格内容,候选单元格背景高亮等:

三、部分代码

cpp 复制代码
//表格填充方案
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文件

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

四、简要分析

获取表格和单元格信息:

cpp 复制代码
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;

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

cpp 复制代码
int rowCount = table->querySubObject("Rows")->dynamicCall("Count()").toInt();
int colCount = table->querySubObject("Columns")->dynamicCall("Count()").toInt();

填充单元格数据:

cpp 复制代码
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);
}

单元格背景高亮:

cpp 复制代码
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

相关推荐
yivifu1 小时前
使用VBA区分简体中文段落和繁体中文段落的方法
word·excel·vba
A.A呐4 小时前
【QT第三章】常用控件2
开发语言·qt
QD_ANJING4 小时前
3月面大厂前端岗总结笔记(含答案)
前端·javascript·笔记·面试·职场和发展·前端框架·pdf
笨笨马甲4 小时前
Qt 实现三维坐标系的方法
开发语言·qt
谁动了我的代码?5 小时前
VNC中使用QT的GDB调试,触发断点时与界面窗口交互导致整个VNC冻结
开发语言·qt·svn
肖恭伟5 小时前
QtCreator Linux ubuntu24.04问题集合
linux·windows·qt
vegetablesssss6 小时前
QT国际化翻译
qt
困死,根本不会6 小时前
Qt Designer 基础操作学习笔记
开发语言·笔记·qt·学习·microsoft
喜欢喝果茶.7 小时前
Qt MQTT部署
开发语言·qt
浅碎时光8077 小时前
Qt 窗口 (菜单 工具栏 状态栏 浮动窗口 对话框)
qt