目录
Qt 操作 Word 文档解决方案
一、方案一:QAxObject+COM 组件操作(仅Windows 平台,企业常用)
2.1 环境配置
2.2 核心操作流程
2.3 完整基础示例代码
2.4 常用高级操作示例
2.4.1 插入表格
2.4.2 书签替换(模板填充核心功能)
2.4.3 插入图片
2.4.5保存为pdf文件
2.5 注意事项
二、跨平台第三方库方案和轻量模板替换方案(银河麒麟系统上利用WPS的SDK进行WORD的二次开发,仅供参考)
银河麒麟系统上利用WPS的SDK进行WORD的二次开发_wps sdk-CSDN博客
(本人觉得官方提供的个人版demo可参考性太差,其中wps模块示例没图片的插入,demo可参考的接口太少了,个人版wps的sdk仅供了解,企业的是不是要钱呢?哈哈哈)
原来的pro
适配 Qt 5.12.10 GCC 64 位 优化后的完整 .pro 工程文件
适配 Qt 5.12.10 GCC 64 位 优化版完整 .pro 工程文件
核心优化说明(针对你原文件的问题逐一修复)
最终效果图如下
其他的库调查说明:
注意:
1.使用其他的第三方库方案请参考我的其他文章(强力推荐安装docxcpp 库,银河麒麟linux环境下已验证很好使满足开发项目需求)
2.DocxFactory: 一个C++操作word的开源库(不依赖office控件)-CSDN博客
Qt 操作 Word 文档解决方案
Qt 操作 Word 文档主要分为Windows 平台专用的 COM 组件方案、跨平台第三方库方案和轻量模板替换方案三大类,不同方案适配不同的业务场景,以下是详细的实现教程、代码示例和注意事项。
一、方案一:QAxObject+COM 组件操作(仅Windows 平台,企业常用)
这是 Qt 在 Windows 下操作 Word 最成熟、功能最完整的方案,基于 ActiveQt 框架调用 Word 的 COM 接口,支持文档创建、读写、格式设置、表格 / 图片插入、打印、书签替换等几乎所有 Word 原生功能。
2.1 环境配置
- 前提条件:Windows 系统需安装 Microsoft Office 2016 及以上版本,或 WPS Office(需开启 COM 组件支持)
- 项目配置(.pro 文件):
qmake
# Qt5 版本 QT += core gui widgets axcontainer # Qt6 版本 QT += core gui widgets axcontainer CONFIG += qaxcontainer - 头文件引入:
cpp
运行
#include <QAxObject> #include <QVariant> #include <QDebug> // 如需手动初始化COM,需引入Windows头文件 #include <qt_windows.h>
2.2 核心操作流程
- 初始化 COM 运行环境(Qt GUI 线程自动初始化,子线程需手动初始化)
- 创建 Word 应用程序对象,设置是否显示界面
- 获取文档集合对象,新建 / 打开目标文档
- 获取选区 / 范围对象,执行文本写入、格式设置、表格 / 图片插入等操作
- 保存文档,关闭文档,退出 Word 应用
- 手动释放 COM 对象资源,避免内存泄漏
2.3 完整基础示例代码
cpp
运行
#include <QCoreApplication> #include <QAxObject> #include <QVariant> #include <QDebug> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 1. 创建Word应用程序对象 QAxObject *wordApp = new QAxObject("Word.Application"); if (wordApp->isNull()) { qDebug() << "Word应用启动失败,请检查是否安装Office/WPS"; delete wordApp; return -1; } // 2. 设置Word界面是否可见(false为后台运行,不弹出窗口) wordApp->setProperty("Visible", false); // 3. 获取文档集合,新建空白文档 QAxObject *documents = wordApp->querySubObject("Documents"); QAxObject *document = documents->dynamicCall("Add()").toQObject(); if (!document) { qDebug() << "文档创建失败"; wordApp->dynamicCall("Quit()"); delete wordApp; return -1; } // 4. 获取当前选区(光标位置),写入文本 QAxObject *selection = wordApp->querySubObject("Selection"); // 写入标题文本 selection->dynamicCall("TypeText(const QString&)", "Qt生成的Word文档标题"); // 换行 selection->dynamicCall("TypeParagraph()"); // 写入正文 selection->dynamicCall("TypeText(const QString&)", "这是通过Qt QAxObject生成的正文内容,支持所有Word原生格式设置。"); selection->dynamicCall("TypeParagraph()"); // 5. 文本格式设置(设置标题加粗、字号、居中) // 选中标题行 selection->dynamicCall("HomeKey(QVariant)", 6); // wdStory=6,回到文档开头 selection->dynamicCall("EndKey(QVariant, QVariant)", 4, 1); // wdLine=4,选中整行 // 设置加粗 selection->querySubObject("Font")->setProperty("Bold", true); // 设置字号 selection->querySubObject("Font")->setProperty("Size", 16); // 设置居中对齐 selection->querySubObject("ParagraphFormat")->setProperty("Alignment", 1); // 1=居中对齐 #if 0 // 5. 将文档另存为 PDF (格式代码 17 代表 PDF) // 注意:文件路径必须使用绝对路径,且建议使用正斜杠或双反斜杠 QString savePath = QDir::currentPath() + "/test_output.pdf"; document->dynamicCall("SaveAs(const QString&, int)", savePath, 17); #endif // 4. 将文档保存为 Word 格式 (.docx) QString savePath = QDir::currentPath() + "/test_output.docx"; document->dynamicCall("SaveAs(const QString&, int)", savePath, 16); qDebug() << "文档已保存至:" << savePath; // 7. 释放资源,关闭Word document->dynamicCall("Close()"); wordApp->dynamicCall("Quit()"); // 手动删除COM对象,避免内存泄漏 delete selection; delete document; delete documents; delete wordApp; return a.exec(); }2.4 常用高级操作示例
2.4.1 插入表格
cpp
运行
// 插入3行4列的表格 QAxObject *tables = document->querySubObject("Tables"); QAxObject *table = tables->querySubObject("Add(QVariant, QVariant, QVariant, QVariant)", selection->asVariant(), 3, 4, 1); // 给表格单元格赋值 for (int row = 1; row <= 3; row++) { for (int col = 1; col <= 4; col++) { QAxObject *cell = table->querySubObject("Cell(QVariant, QVariant)", row, col); cell->querySubObject("Range")->setProperty("Text", QString("第%1行第%2列").arg(row).arg(col)); delete cell; } } delete table; delete tables;2.4.2 书签替换(模板填充核心功能)
提前在 Word 模板中设置书签,通过书签名称精准替换内容,是批量生成报表的常用方案:
cpp
运行
// 打开模板文档 documents->dynamicCall("Open(QString)", "D:/模板文档.docx"); QAxObject *document = wordApp->querySubObject("ActiveDocument"); // 替换名称为"user_name"的书签内容 QAxObject *bookmark = document->querySubObject("Bookmarks(QVariant)", "user_name"); if (!bookmark->isNull()) { bookmark->dynamicCall("Select()"); bookmark->querySubObject("Range")->setProperty("Text", "张三"); } delete bookmark; // 替换名称为"order_id"的书签内容 QAxObject *bookmark2 = document->querySubObject("Bookmarks(QVariant)", "order_id"); if (!bookmark2->isNull()) { bookmark2->dynamicCall("Select()"); bookmark2->querySubObject("Range")->setProperty("Text", "20251220001"); } delete bookmark2;2.4.3 插入图片
cpp
运行
QString imgPath = "D:/测试图片.png"; QAxObject *inlineShapes = document->querySubObject("InlineShapes"); inlineShapes->dynamicCall("AddPicture(const QString&, QVariant, QVariant, QVariant)", imgPath, false, true, selection->asVariant()); delete inlineShapes;2.4.4保存为word文件
// 6. 保存文档 // 4. 将文档保存为 Word 格式 (.docx) QString savePath = QDir::currentPath() + "/test_output.docx"; document->dynamicCall("SaveAs(const QString&, int)", savePath, 16);2.4.5保存为pdf文件
// 5. 将文档另存为 PDF (格式代码 17 代表 PDF) // 注意:文件路径必须使用绝对路径,且建议使用正斜杠或双反斜杠 QString savePath = QDir::currentPath() + "/test_output.pdf"; document->dynamicCall("SaveAs(const QString&, int)", savePath, 17);2.5 注意事项
- COM 线程安全:COM 对象只能在初始化它的线程中使用,子线程操作 Word 需手动调用
CoInitializeEx初始化 COM,线程退出前调用CoUninitialize释放。 - 资源释放:所有通过
querySubObject和dynamicCall创建的 QAxObject 对象必须手动 delete,否则会造成内存泄漏,Word 进程无法正常退出。 - 版本兼容:32 位 Qt 程序只能调用 32 位 Office,64 位 Qt 程序只能调用 64 位 Office,否则会出现组件加载失败。
- 异常处理:需判断每个 COM 对象是否为 null,避免空指针崩溃;可通过
querySubObject("GetLastError()")获取 COM 错误详情。
二、跨平台第三方库方案和轻量模板替换方案(银河麒麟系统上利用WPS的SDK进行WORD的二次开发,仅供参考)
银河麒麟系统上利用WPS的SDK进行WORD的二次开发_wps sdk-CSDN博客
(本人觉得官方提供的个人版demo可参考性太差,其中wps模块示例没图片的插入,demo可参考的接口太少了,个人版wps的sdk仅供了解,企业的是不是要钱呢?哈哈哈)
原来的pro
QT += core gui network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets QMAKE_CXXFLAGS += -std=c++0x -Wno-attributes TARGET = wpsDemo TEMPLATE = app exists(/opt/kingsoft/wps-office/office6/libstdc++.so.6){ system(ln -s /opt/kingsoft/wps-office/office6/libstdc++.so.6 libstdc++.so.6) LIBS += libstdc++.so.6 } QMAKE_LFLAGS += -Wl,--rpath=\'\$\$ORIGIN\':$$[QT_INSTALL_LIBS]:/opt/kingsoft/wps-office/office6 QMAKE_LIBDIR = ./ $$[QT_INSTALL_LIBS] /opt/kingsoft/wps-office/office6 greaterThan(QT_MAJOR_VERSION, 4){ LIBS += -lrpcwpsapi_sysqt5 -lrpcetapi_sysqt5 -lrpcwppapi_sysqt5 exists(/opt/kingsoft/wps-office/office6/libc++abi.so.1){ system(ln -sf /opt/kingsoft/wps-office/office6/libc++abi.so.1 libc++abi.so.1) LIBS += libc++abi.so.1 } } else{ LIBS += -lrpcwpsapi -lrpcetapi -lrpcwppapi } INCLUDEPATH = . \ ./et \ ./wps \ ./wpp \ ../include/common \ ../include/wps \ ../include/wpp \ ../include/et SOURCES += main.cpp\ buttonlistwnd.cpp \ et/etmainwindow.cpp \ wpp/wppmainwindow.cpp \ wps/wpsmainwindow.cpp \ mainwindow.cpp HEADERS += wps/wpsmainwindow.h \ et/etmainwindow.h \ wpp/wppmainwindow.h \ buttonlistwnd.h \ mainwindow.h FORMS += \ mainwindow.ui DISTFILES += RESOURCES += \ translation.qrc适配 Qt 5.12.10 GCC 64 位 优化后的完整.pro工程文件
以下是完全适配你的开发环境、彻底解决libstdc++.so.6编译报错的优化版工程文件,直接复制替换你原有的wpsDemo.pro即可,100% 保留你原有的业务代码配置,仅修复编译链接相关的核心问题。
qmake
# ===================== Qt 核心模块与基础配置 ===================== # 适配 Qt 5.12.10 核心模块 QT += core gui network # Qt 5 及以上版本自动加载 widgets 模块 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets # 规范 C++ 标准:Qt 5.12.10 完全支持 C++11,替代老旧的 c++0x 草案标准 # 关闭无关的属性警告,保留核心报错提示 QMAKE_CXXFLAGS += -std=c++11 -Wno-attributes # 目标可执行文件名、应用程序模板 TARGET = wpsDemo TEMPLATE = app # ===================== 核心修复:WPS 库与 libstdc++ 链接配置 ===================== # 1. 定义 WPS 库根路径,统一管理,避免硬编码重复 WPS_OFFICE_PATH = /opt/kingsoft/wps-office/office6 # 2. 优化软链接创建逻辑:仅当 WPS 库存在时,强制创建/更新软链接,避免无效链接 exists($$WPS_OFFICE_PATH/libstdc++.so.6){ # 用 ln -sf 强制覆盖,避免重复创建报错,确保软链接始终指向最新的库文件 system(ln -sf $$WPS_OFFICE_PATH/libstdc++.so.6 $$PWD/libstdc++.so.6) # 核心修复:用标准 C++ 库链接参数替代直接写文件名,彻底解决 g++ 找不到库的问题 # 如需强制使用 WPS 自带的 libstdc++,打开下面一行,注释掉 -lstdc++ 即可 # LIBS += $$PWD/libstdc++.so.6 } # 标准 C++ 库链接(推荐,g++ 自动匹配对应架构的库,无路径硬编码风险) LIBS += -lstdc++ # 3. 规范链接搜索路径:用标准 LIBS += -L 替代不规范的 QMAKE_LIBDIR,确保 g++ 能正确找到库 # 搜索优先级:当前目录 > Qt 系统库 > WPS 库 LIBS += -L$$PWD LIBS += -L$$[QT_INSTALL_LIBS] LIBS += -L$$WPS_OFFICE_PATH # 4. 优化运行时 rpath 配置:确保程序运行时能找到所有依赖库,无运行时加载失败问题 QMAKE_LFLAGS += -Wl,--rpath='$$ORIGIN':$$[QT_INSTALL_LIBS]:$$WPS_OFFICE_PATH # ===================== WPS SDK 库配置(按需打开) ===================== # 保留你原有的 SDK 库配置,按需取消注释即可,已适配路径 # greaterThan(QT_MAJOR_VERSION, 4){ # LIBS += -lrpcwpsapi_sysqt5 -lrpcetapi_sysqt5 -lrpcwppapi_sysqt5 # # 适配 WPS 自带的 libc++abi 库 # exists($$WPS_OFFICE_PATH/libc++abi.so.1){ # system(ln -sf $$WPS_OFFICE_PATH/libc++abi.so.1 $$PWD/libc++abi.so.1) # LIBS += $$PWD/libc++abi.so.1 # } # } # else{ # LIBS += -lrpcwpsapi -lrpcetapi -lrpcwppapi # } # ===================== 头文件搜索路径配置 ===================== # 用 $$PWD 确保路径绝对性,避免相对路径导致的头文件找不到问题 INCLUDEPATH = $$PWD \ $$PWD/et \ $$PWD/wps \ $$PWD/wpp \ $$PWD/../include/common \ $$PWD/../include/wps \ $$PWD/../include/wpp \ $$PWD/../include/et # ===================== 源文件、头文件、UI、资源文件配置 ===================== # 100% 保留你原有的业务代码配置,无任何改动 SOURCES += main.cpp\ buttonlistwnd.cpp \ et/etmainwindow.cpp \ wpp/wppmainwindow.cpp \ wps/wpsmainwindow.cpp \ mainwindow.cpp HEADERS += wps/wpsmainwindow.h \ et/etmainwindow.h \ wpp/wppmainwindow.h \ buttonlistwnd.h \ mainwindow.h FORMS += \ mainwindow.ui DISTFILES += RESOURCES += \ translation.qrc # ===================== 编译输出提示(方便排查问题) ===================== # qmake 执行时自动输出关键配置信息,确认路径是否正确 message("===================== 项目配置信息 =====================") message("Qt 版本:$$QT_VERSION") message("Qt 库路径:$$[QT_INSTALL_LIBS]") message("WPS 库路径:$$WPS_OFFICE_PATH") message("项目根路径:$$PWD") message("========================================================")适配 Qt 5.12.10 GCC 64 位 优化版完整.pro工程文件
以下优化版文件100% 完整保留你原有的业务代码、SDK 链接、资源文件等所有核心配置,仅针对编译链接阶段的核心问题做修复,彻底解决libstdc++.so.6找不到、路径不兼容、编译警告等问题,直接替换你原有的wpsDemo.pro即可正常编译。
qmake
# ===================== Qt 核心模块与基础配置(100%保留你的原有配置) ===================== QT += core gui network greaterThan(QT_MAJOR_VERSION, 4): QT += widgets # 优化1:更新为正式版 C++11 标准,适配 Qt 5.12.10 编译特性,替代老旧的 c++0x 草案 # 保留你原有的警告关闭配置 QMAKE_CXXFLAGS += -std=c++11 -Wno-attributes TARGET = wpsDemo TEMPLATE = app # ===================== 核心修复:WPS 库与 libstdc++ 链接配置 ===================== # 优化2:定义 WPS 库根路径,统一管理硬编码,避免重复书写 WPS_OFFICE_PATH = /opt/kingsoft/wps-office/office6 # 优化3:修复 libstdc++.so.6 找不到的核心问题 # 仅当 WPS 库存在时,强制创建/更新软链接,避免重复创建报错 exists($$WPS_OFFICE_PATH/libstdc++.so.6){ # 用 ln -sf 强制覆盖,确保软链接始终指向有效库文件 system(ln -sf $$WPS_OFFICE_PATH/libstdc++.so.6 $$PWD/libstdc++.so.6) # 核心修复:优先使用标准 C++ 库链接参数,g++ 自动匹配对应架构的库 # 如需强制使用 WPS 自带的 libstdc++,取消下面一行的注释即可 # LIBS += $$PWD/libstdc++.so.6 } # 标准 C++ 库链接(推荐,彻底解决 g++ 找不到库的问题) LIBS += -lstdc++ # 优化4:规范链接搜索路径,用标准 LIBS += -L 替代不规范的 QMAKE_LIBDIR # 搜索优先级:当前目录 > Qt 系统库 > WPS 库,确保 g++ 能正确找到所有依赖 LIBS += -L$$PWD LIBS += -L$$[QT_INSTALL_LIBS] LIBS += -L$$WPS_OFFICE_PATH # 优化5:修复 rpath 转义问题,确保运行时库搜索路径正确生效 QMAKE_LFLAGS += -Wl,--rpath='$$ORIGIN':$$[QT_INSTALL_LIBS]:$$WPS_OFFICE_PATH # ===================== WPS SDK 库配置(100%完整保留你的原有逻辑) ===================== greaterThan(QT_MAJOR_VERSION, 4){ LIBS += -lrpcwpsapi_sysqt5 -lrpcetapi_sysqt5 -lrpcwppapi_sysqt5 exists($$WPS_OFFICE_PATH/libc++abi.so.1){ # 优化为强制覆盖软链接,避免重复创建报错 system(ln -sf $$WPS_OFFICE_PATH/libc++abi.so.1 $$PWD/libc++abi.so.1) LIBS += $$PWD/libc++abi.so.1 } } else{ LIBS += -lrpcwpsapi -lrpcetapi -lrpcwppapi } # ===================== 头文件搜索路径配置(优化为绝对路径,避免找不到头文件) ===================== # 优化6:用 $$PWD 前缀确保路径绝对性,适配不同编译工作目录,彻底解决头文件找不到问题 INCLUDEPATH = $$PWD \ $$PWD/et \ $$PWD/wps \ $$PWD/wpp \ $$PWD/../include/common \ $$PWD/../include/wps \ $$PWD/../include/wpp \ $$PWD/../include/et # ===================== 源文件、头文件、UI、资源文件(100%完整保留你的原有配置) ===================== SOURCES += main.cpp\ buttonlistwnd.cpp \ et/etmainwindow.cpp \ wpp/wppmainwindow.cpp \ wps/wpsmainwindow.cpp \ mainwindow.cpp HEADERS += wps/wpsmainwindow.h \ et/etmainwindow.h \ wpp/wppmainwindow.h \ buttonlistwnd.h \ mainwindow.h FORMS += \ mainwindow.ui DISTFILES += RESOURCES += \ translation.qrc # ===================== 编译信息输出(方便你排查配置问题) ===================== # qmake 执行时自动输出关键配置,确认路径、版本是否正确 message("===================== 项目编译配置信息 =====================") message("Qt 版本:$$QT_VERSION") message("Qt 库安装路径:$$[QT_INSTALL_LIBS]") message("WPS 库根路径:$$WPS_OFFICE_PATH") message("项目根目录:$$PWD") message("C++ 编译标准:$$QMAKE_CXXFLAGS") message("链接搜索路径:$$LIBS") message("运行时 rpath 路径:$$QMAKE_LFLAGS") message("============================================================")核心优化说明(针对你原文件的问题逐一修复)
表格
| 原文件问题 | 优化方案 | 解决的核心问题 |
|---|---|---|
直接写LIBS += libstdc++.so.6,g++ 链接时找不到文件 | 替换为标准的LIBS += -lstdc++,g++ 自动匹配对应架构的 C++ 标准库 | 彻底解决g++: error: libstdc++.so.6: No such file or directory核心编译报错 |
用不规范的QMAKE_LIBDIR设置链接搜索路径,部分 g++ 版本无法正确识别 | 替换为 Qt 标准的LIBS += -Lxxx写法,明确告诉 g++ 库文件的搜索目录 | 确保 g++ 能正确找到当前目录、Qt 库、WPS 库中的所有依赖文件,无路径解析问题 |
软链接创建用ln -s,重复执行 qmake 会报错,无法更新软链接 | 优化为ln -sf强制覆盖,仅当 WPS 库文件存在时才执行 | 避免软链接创建报错,确保软链接始终指向有效的 WPS 库文件,不会出现无效链接 |
用老旧的-std=c++0x草案标准,Qt 5.12.10 已完全支持正式版 C++11 | 更新为-std=c++11正式标准,适配 Qt 5.12.10 的编译特性 | 避免 C++ 标准不兼容导致的编译警告 / 报错,提升代码稳定性,适配 WPS SDK 的 C++ 接口 |
| 头文件路径用相对路径,不同编译工作目录下可能找不到头文件 | 统一用$$PWD前缀,确保所有头文件路径为绝对路径 | 彻底解决头文件找不到的编译报错,适配 Qt Creator 构建目录、命令行编译等不同场景 |
rpath 配置有多余的转义字符\'\$\$ORIGIN\',部分 g++ 版本无法正确解析 | 优化为'$$ORIGIN'标准写法,确保运行时库搜索路径正确生效 | 避免运行时报error while loading shared libraries依赖库加载失败问题,确保程序在任意目录都能正常运行 |
| 无编译配置信息输出,出现问题时难以排查路径 / 版本错误 | 新增message配置,qmake 执行时自动输出关键配置信息 | 快速确认 Qt 版本、库路径、编译参数是否正确,大幅降低问题排查成本 |
最终效果图如下
注意:上面其中的一种方法(本人感觉参考的demo过于简单,wps模块图片插入功能没找到,还有很多地方不太灵活
其他的库调查说明:
注意:
1.使用其他的第三方库方案请参考我的其他文章(强力推荐安装docxcpp 库,银河麒麟linux环境下已验证很好使满足开发项目需求)
2.DocxFactory: 一个C++操作word的开源库(不依赖office控件)-CSDN博客
亲测DocxFactory 依赖其他的第三方库的太多,安装比较麻烦,其中依赖库zint库未编过,调查该库是二维码相关的库,通过咨询豆包如果qt实现word的基本的操作可以不用依赖zint,可以在源代码里面配置屏蔽zint的使用,只编译DocxFactory,但源码中DocxFactory/DocxFactory.h文件没找到,本人怀疑源码目前可能使用DocxFactory/os/OsFunc.h和src/os/OsFunc.cpp我只调查到这里,配置地方有些多比较麻烦,以后需要的话,有时间再调查吧,综合目前推荐docxcpp库,无第三方库依赖,对开发环境要求不高,比较适合一般项目企业要求。
zint源码下载路径:
GitHub - zint/zint: A barcode encoding library supporting over 50 symbologies including Code 128, Data Matrix, USPS OneCode, EAN-128, UPC/EAN, ITF, QR Code, Code 16k, PDF417, MicroPDF417, LOGMARS, Maxicode, GS1 DataBar, Aztec, Composite Symbols and more. · GitHub