当前位置: 首页 > news >正文

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;///JsonQJsonDocument 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~25QJsonObject 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); //另存为wordqDebug() << "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

http://www.lryc.cn/news/520765.html

相关文章:

  • vue3+ts的几个bug调试
  • DVWA靶场CSRF漏洞通关教程及源码审计
  • 前端开发:HTML常见标签
  • 【机器学习】主动学习-增加标签的操作方法-样本池采样(Pool-Based Sampling)
  • 【Rust自学】11.9. 单元测试
  • 深入理解Web存储机制:Cookie、SessionStorage与LocalStorage的区别
  • SpringBoot之BeanDefinitionLoader类源码学习
  • 【芯片封测学习专栏 -- 2D | 2.5D | 3D 封装的区别和联系】
  • 从硬件设备看Linux
  • open3d+opencv实现矩形框裁剪点云操作(C++)
  • git 本地操作
  • PL/SQL语言的文件操作
  • linux lsof 和 fuser命令介绍
  • [Python学习日记-76] 网络编程中的 socket 开发 —— 介绍、工作流程、socket 模块用法和函数介绍
  • vue(七) vue进阶
  • [Transformer] The Structure of GPT, Generative Pretrained Transformer
  • Django Admin 自定义操作封装
  • http和https有哪些不同
  • PL/SQL语言的数据库交互
  • 亿道三防丨三防笔记本是什么意思?和普通笔记本的优势在哪里?
  • 从项目代码看 React:State 和 Props 的区别及应用场景实例讲解
  • Vue 学习之旅:核心技术学习总结与实战案例分享(vue指令下+计算属性+侦听器)
  • freertos的基础(二)内存管理:堆和栈
  • vue \n 换行不不显示
  • GPT 系列论文精读:从 GPT-1 到 GPT-4
  • 在 Ubuntu 上安装和配置 Redis
  • Excel中双引号问题
  • 【机器学习】主动学习-增加标签的操作方法-流式选择性采样(Stream-based selective sampling)
  • elementUI项目中,只弹一个【token过期提示】信息框的处理
  • SpringBoot开发—— SpringBoot中如何实现 HTTP 请求的线程隔离