Qt+Pyhton实现麒麟V10系统下word文档读写功能

2023-11-06

前言

我最近遇到一个这样的需求,即把某个软件中采集的数据按照特定的格式导出到world文档中。因为程序是用Qt开发的,所以想找一个满足要求的C++库,通过一番查询发现能完成这个需求的常用C++库有LibreOffice、OpenOffice。这两个库虽然能实现这一需求但是学习成本比较高,在规定的时间内完成这个需求比较困难。

这时只能将目光转向其他语言的读写word文档的库上,我发现python-docx 这个库不仅能实现需求而且学习成本很低,只要懂点Python几乎不需要额外花时间就能学会使用这个库。

本文主要从三个方面介绍了如何在Qt应用程序中调用Python实现数据导出到world文档中。这三个方面分别是C++调用python、在程序中使用Python虚拟环境及Python-docx库的基本应用。

1.C++调用python

1.1 安装Python开发环境

麒麟V10 默认安装了python3.8,但是没有安装C++调用Python需的头文件,在系统中找不到Python.h文件。安装Python 开发环境,执行下面的命令:

sudo apt-get update 
sudo apt-get install python3-dev

安装完成后会在/usr/include/python3.8 目录下看到需要的头文件。

1.2 修改Qt工程配置

新建Qt工程demo,并在pro文件中增加Python头文件和库的引用。

INCLUDEPATH += /usr/include/python3.8
LIBS += -L/usr/lib/python3.8/config-3.8-aarch64-linux-gnu -lpython3.8

1.3 初始化Python环境

 	//初始化Python C API
    Py_Initialize();
	
	//将Python文件所在的目录添加到环境变量,以便能正确加载Python文件。
    PyRun_SimpleString("import sys");
    QString pyfilePath = QString::fromLocal8Bit("sys.path.append('%1')").arg(qApp->applicationDirPath() + "/python");
    qDebug() << "pyfilePath:" << pyfilePath;
    PyRun_SimpleString(pyfilePath.toLocal8Bit().data());
    
    QString printSysPath = "print(sys.path)";
    PyRun_SimpleString(printSysPath.toLocal8Bit().data());
	
	//加载Python文件,其中testdocx.py 所在的目录即为 qApp->applicationDirPath() + /python/testdocx.py
    PyObject *pWriteWordModule = PyImport_ImportModule("testdocx");
    if(!pWriteWordModule)
    {
        qDebug() << "import module faild!";
        //如果失败打印错误,方便调试
        PyErr_Print();
    }

上面的代码,首先初始化Python环境,然后设置Python文件搜索路径到path中,最后加载testdocx.py 文件。

1.4 C++ 调用Python 函数

假设testdocx.py 文件中的内容如下,定义了一个函数,并打印传进来的参数。

def writeWord(wordPath):
    print(wordPath)

在C++中调用这个函数

	//获取Python中定义的函数的指针
 	PyObject *pFunc = PyObject_GetAttrString(pWriteWordModule, "writeWord");
    if(!pFunc)
    {
        qDebug() << "get func faild!";
    }
	//初始化参数元组,其中包含一个参数
    PyObject *pTuple = PyTuple_New(1);
    QString wordFilePath = QString("%1/python/%2").arg(qApp->applicationDirPath()).arg(QString::fromLocal8Bit("xxx.docx"));
    //设置参数
    PyTuple_SetItem(pTuple, 0, Py_BuildValue("s", wordFilePath.toLocal8Bit().data()));
    //调用Python中的函数
    PyObject_CallObject(pFunc, pTuple);

运行程序,如果一切顺利的话会在终端打印:
/home/demo/bin/python/xxx.docx

1.5 常用的Python接口

Python C API参考文档地址
在这里插入图片描述

PyObject 在C++和Python混合编程中最常用的一个类型,所有对象类型都是这个类型的扩展。PyObject中包含了Python需要将对象的指针视为对象的信息。在一般的“release”版本中,它只包含对象的引用计数和指向相应类型对象的指针。实际上并没有任何东西被声明为PyObject,但是每个指向Python对象的指针都可以转换为PyObject*。必须使用宏Py_REFCNT和Py_TYPE来访问成员。下面是一些编程中常用的Python C API。

  • PyList_New 创建一个Python list 对象,返回类型为PyObject*;
  • PyDict_New 创建一个Python Dict 对象,返回类型为PyObject*;
  • PyTuple_New 创建一个Python 元组对象,返回类型为PyObject*;
  • Py_BuildValue 将C数据类型转换为Python对象,返回类型为PyObject*,下面是Py_BuildValue函数的原型:
    PyObject* Py_BuildValue(const char* format, …);其中,format是一个描述返回的Python对象的格式字符串,而…表示可变数量的参数列表,这些参数与格式字符串中指定的类型相对应。
    下面是一些常见的格式字符串和相应的参数列表:
    ‘()’:表示一个空元组。
    ‘(i)’:表示一个包含一个整数(参数为整数)的元组。
    ‘(ii)’:表示一个包含两个整数(参数为两个整数)的元组。
    ‘s’:表示一个字符串。
    ‘d’:表示一个浮点数。
    ‘z’:表示一个NULL指针或None。
    ‘O’:表示一个通用对象。
    下面是一个示例,演示如何使用Py_BuildValue函数将C数据类型转换为Python对象:
#include <Python.h>
int main(int argc, char* argv[]) {
    Py_Initialize();
    int x = 42;
    double y = 3.14;
    char* z = "Hello, World!";

    PyObject* result = Py_BuildValue("(iO)", x, Py_None);
    if (result == NULL) {
        PyErr_Print();
        return 1;
    }

    printf("Result: %s\n", PyUnicode_AsUTF8(result));

    Py_DECREF(result);
    Py_Finalize();
    return 0;
}
  • PyDict_SetItemString 设置字典键值对;
//函数原型
PyAPI_FUNC(int) PyDict_SetItemString(PyObject *dp, const char *key, PyObject *item);
//示例:
PyObject* pDictObj = PyDict_New();
PyObject* deviceNameObj = Py_BuildValue("s", deviceData.deviceName.toLocal8Bit().data());
PyDict_SetItemString(pDictObj, "deviceName", deviceNameObj);
  • PyList_Append 向列表中添加元素;
//函数原型
PyAPI_FUNC(int) PyList_Append(PyObject *, PyObject *);
//示例:
PyObject *PointDataListObj = PyList_New(0);
PyList_Append(PointDataListObj, pDictObj);
  • PyRun_SimpleString 在Python解释器中执行一个简单的 Python 代码字符串;
//函数原型
int PyRun_SimpleString(const char *command);
//示例
const char* code = "print('Hello, World!')";
int result = PyRun_SimpleString(code);
if (result == 0) {
	//执行成功
    printf("Successfully executed code.\n");
} else {
	//执行失败
    printf("Failed to execute code.\n");
}
  • PyImport_ImportModule 在C程序中导入Python模块;
//函数原型
PyObject* PyImport_ImportModule(const char *name);
//说明,该函数返回一个Python对象,表示导入的模块。如果导入成功,则返回该模块对象的引用,否则返回NULL。
//示例:
PyObject* mymodule = PyImport_ImportModule("mymodule");
if (mymodule != NULL) {
    printf("Successfully imported mymodule.\n");
} else {
    printf("Failed to import mymodule.\n");
}
  • PyObject_CallObject 在C中调用Python对象的方法和函数;
//函数原型
PyObject* PyObject_CallObject(PyObject *callable, PyObject *args);
//说明,callable是一个指向要调用的Python对象(如函数或方法)的指针,args是一个指向参数列表的指针。
//该函数返回调用结果,表示为Python对象。如果调用成功,则返回调用结果的引用,否则返回NULL。

//示例:
PyObject* mymodule = PyImport_ImportModule("mymodule");
PyObject* myfunction = PyObject_GetAttrString(mymodule, "myfunction");
PyObject* args = PyTuple_New(1);
PyTuple_SetItem(args, 0, PyLong_FromLong(42));

PyObject* result = PyObject_CallObject(myfunction, args);
if (result != NULL) {
    printf("Function returned: %ld\n", PyLong_AsLong(result));
} else {
    printf("Failed to call function.\n");
}
  • PyErr_Print 用于将当前错误信息打印到标准错误输出,方便调试程序。

2.python虚拟环境

2.1Python虚拟环境简介

virtualenv和anaconda都是用于创建Python虚拟环境的工具,二者的主要区别如下:

  1. 包管理器:virtualenv使用pip作为包管理器,而anaconda使用conda作为包管理器。
  2. 环境隔离:virtualenv只能隔离Python包,而anaconda可以隔离整个Python环境及其依赖项。
  3. 系统依赖:anaconda自带了许多科学计算所需的系统依赖,而virtualenv则需要手动安装这些依赖。
  4. 平台支持:anaconda支持Windows、Linux和MacOS等多个平台,而virtualenv则主要支持Linux和MacOS。

在这里选择virtualenv,原因是anaconda 在飞腾架构的麒麟系统上安装失败。

2.2 virtualenv 安装及使用

  • 1.安装
 sudo apt-get install pip
 pip install virtualenv
  • 2.创建虚拟环境
cd /home/demo/bin/python
virtualenv demoEnv
#或者指定Python版本
virtualenv -p /usr/bin/python3.8 demoEnv
  • 3.激活虚拟环境
demoEnv\Scripts\activate
  • 4.安装依赖包
pip install -r requirements.txt
pip install python-docx
  • 5.退出虚拟环境
demoEnv\Scripts\deactivate

2.3 在C++程序中配置virtualenv 虚拟环境

demo程序利用了系统自带的Python3.8环境,所以在C++程序中只需配置好虚拟环境的包安装目录即可,这点是参考在终端通过命令执行Python脚本时的环境设置。例如执行下面的命令来查看当前Python环境的path内容:

python3 test.py
#其中 test.py 内容如下
import sys
print(sys.path)

因此Qt程序中Python环境初始化部分要增加设置Python虚拟环境安装包路径的代码,如下:

    QString modulePath = QString::fromLocal8Bit("sys.path.append('%1')").arg(qApp->applicationDirPath() + "/python/demoEnv/lib/python3.8/site-packages");
    PyRun_SimpleString(modulePath.toLocal8Bit().data());

经过上述设置就可以在虚拟环境中用pip命令安装应用程序所需的python包,并在应用程序所在目录的python文件中使用第三方包,如python-docx。当Qt程序需要发布到其他飞腾架构的麒麟V10设备上时,可以直接把虚拟环境一起打包,省去了在新的设备安装依赖包的步骤。

3.python-docx库的应用

官方参考文档https://python-docx.readthedocs.io
在这里插入图片描述
python-docx 作为word文档读写库算是很轻量了,其涉及的概念不多,很容易理解与掌握。下面是python-docx的一些核心概念。

  • Document 表示word文档。
  • Text 表示word文档中的文本和段落。
  • Section 表示页面布局,方向相同的页面。
  • Headers 、 Footers 表示页眉页脚
  • Table 表格
  • Image 图片

下面是一个快速上手指南:

  1. 打开一个word文档
from docx import Document
document = Document()
  1. 添加一个段落
paragraph = document.add_paragraph('Lorem ipsum dolor sit amet.')
或
prior_paragraph = paragraph.insert_paragraph_before('Lorem ipsum')
  1. 添加页眉
document.add_heading('The REAL meaning of the universe')
或
document.add_heading('The role of dolphins', level=2)
  1. 添加分页符
document.add_page_break()
  1. 添加表格
table = document.add_table(rows=2, cols=2)
cell = table.cell(0, 1)
cell.text = 'parrot, possibly dead'
row = table.rows[1]
row.cells[0].text = 'Foo bar to you.'
row.cells[1].text = 'And a hearty foo bar to you too sir!'
for row in table.rows:
    for cell in row.cells:
        print(cell.text)
row_count = len(table.rows)
col_count = len(table.columns)
row = table.add_row()
# get table data -------------
items = (
    (7, '1024', 'Plush kittens'),
    (3, '2042', 'Furbees'),
    (1, '1288', 'French Poodle Collars, Deluxe'),
)

# add table ------------------
table = document.add_table(1, 3)

# populate header row --------
heading_cells = table.rows[0].cells
heading_cells[0].text = 'Qty'
heading_cells[1].text = 'SKU'
heading_cells[2].text = 'Description'

# add a data row for each item
for item in items:
    cells = table.add_row().cells
    cells[0].text = str(item.qty)
    cells[1].text = item.sku
    cells[2].text = item.desc
table.style = 'LightShading-Accent1'
  1. 添加一个图片
document.add_picture('image-filename.png')
#设置图片尺寸
from docx.shared import Inches
document.add_picture('image-filename.png', width=Inches(1.0))

4.总结

以上就是本篇的所有内容了,关于python-docx应用的一些细节本文并未涉及太多,想要了解更多的话还是要阅读官方文档。对C++ python混合编程有疑问的朋友欢迎留言讨论!!!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt+Pyhton实现麒麟V10系统下word文档读写功能 的相关文章

  • 如何将 ascii 值列表转换为 python 中的字符串?

    我在 Python 程序中有一个列表 其中包含一系列数字 这些数字本身就是 ASCII 值 如何将其转换为可以在屏幕上回显的 常规 字符串 您可能正在寻找 chr gt gt gt L 104 101 108 108 111 44 32 1
  • pandas - 包含时间序列数据的堆积条形图

    我正在尝试使用时间序列数据在 pandas 中创建堆积条形图 DATE TYPE VOL 0 2010 01 01 Heavy 932 612903 1 2010 01 01 Light 370 612903 2 2010 01 01 Me
  • 从 Linux 内核模块中调用用户空间函数

    我正在编写一个简单的 Linux 字符设备驱动程序 以通过 I O 端口将数据输出到硬件 我有一个执行浮点运算的函数来计算硬件的正确输出 不幸的是 这意味着我需要将此函数保留在用户空间中 因为 Linux 内核不能很好地处理浮点运算 这是设
  • 将 Matlab 的 datenum 格式转换为 Python

    我刚刚开始从 Matlab 迁移到 Python 2 7 在读取 mat 文件时遇到一些问题 时间信息以 Matlab 的日期数字格式存储 对于那些不熟悉它的人 日期序列号将日历日期表示为自固定基准日期以来已经过去的天数 在 MATLAB
  • 如何使用 Python 3 检查目录是否包含文件

    我到处寻找这个答案但找不到 我正在尝试编写一个脚本来搜索特定的子文件夹 然后检查它是否包含任何文件 如果包含 则写出该文件夹的路径 我已经弄清楚了子文件夹搜索部分 但检查文件却难倒了我 我发现了有关如何检查文件夹是否为空的多个建议 并且我尝
  • 在 Google App Engine 中,如何避免创建具有相同属性的重复实体?

    我正在尝试添加一个事务 以避免创建具有相同属性的两个实体 在我的应用程序中 每次看到新的 Google 用户登录时 我都会创建一个新的播放器 当新的 Google 用户在几毫秒内进行多个 json 调用时 我当前的实现偶尔会创建重复的播放器
  • 外键与独立关系 - Entity Framework 5 有改进吗?

    我读过了several http www ladislavmrnka com 2011 05 foreign key vs independent associations in ef 4 文章和问题 https stackoverflow
  • CMake 无法确定目标的链接器语言

    首先 我查看了this https stackoverflow com questions 11801186 cmake unable to determine linker language with c发帖并找不到解决我的问题的方法 我
  • AES 128 CBC 蒙特卡罗测试

    我正在 AES 128 CBC 上执行 MCT 如中所述http csrc nist gov groups STM cavp documents aes AESAVS pdf http csrc nist gov groups STM ca
  • 如果 PyPy 快 6.3 倍,为什么我不应该使用 PyPy 而不是 CPython?

    我已经听到很多关于PyPy http en wikipedia org wiki PyPy项目 他们声称它比现有技术快 6 3 倍CPython http en wikipedia org wiki CPython口译员开启他们的网站 ht
  • 将 MQTTNet 服务器与 MQTT.js 客户端结合使用

    我已经启动了一个 MQTT 服务器 就像this https github com chkr1011 MQTTnet tree master例子 该代码托管在 ASP Net Core 2 0 应用程序中 但我尝试过控制台应用程序 但没有成
  • 为什么 gcc 抱怨“错误:模板参数 '0' 的类型 'intT' 取决于模板参数”?

    我的编译器是gcc 4 9 0 以下代码无法编译 template
  • 将索引与值交换的最快方法

    考虑pd Series s s pd Series list abcdefghij list ABCDEFGHIJ s A a B b C c D d E e F f G g H h I i J j dtype object 交换索引和值并
  • 调用堆栈中的“外部代码”是什么意思?

    我在 Visual Studio 中调用一个方法 并尝试通过检查调用堆栈来调试它 其中一些行标记为 外部代码 这到底是什么意思 方法来自 dll已被处决 外部代码 意味着该dll没有可用的调试信息 你能做的就是在Call Stack窗口中单
  • 如果没有抽象成员,基类是否应该标记为抽象?

    如果一个类没有抽象成员 可以将其标记为抽象吗 即使没有实际理由直接实例化它 除了单元测试 是的 将不应该实例化的基类显式标记为抽象是合理且有益的 即使在没有抽象方法的情况下也是如此 它强制执行通用准则来使非叶类抽象 它阻止其他程序员创建该类
  • 方法优化 - C#

    我开发了一种方法 允许我通过参数传入表 字符串 列数组 字符串 和值数组 对象 然后使用这些参数创建参数化查询 虽然它工作得很好 但代码的长度以及多个 for 循环散发出一种代码味道 特别是我觉得我用来在列和值之间插入逗号的方法可以用不同的
  • 如何部署“SQL Server Express + EF”应用程序

    这是我第一次部署使用 SQL Server Express 数据库的应用程序 我首先使用实体 框架模型来联系数据库 我使用 Install Shield 创建了一个安装向导来安装应用程序 这些是我在目标计算机中安装应用程序所执行的步骤 安装
  • 无法接收 UDP Windows RT

    我正在为 Windows 8 RT 编写一个 Windows Store Metro Modern RT 应用程序 需要在端口 49030 上接收 UDP 数据包 但我似乎无法接收任何数据包 我已按照使用教程进行操作DatagramSock
  • NLTK:查找单词大小为 2k 的上下文

    我有一个语料库 我有一个词 对于语料库中该单词的每次出现 我想获取一个包含该单词之前的 k 个单词和该单词之后的 k 个单词的列表 我在算法上做得很好 见下文 但我想知道 NLTK 是否提供了一些我错过的功能来满足我的需求 def size
  • 如何将 PostgreSql 与 EntityFramework 6.0.2 集成? [复制]

    这个问题在这里已经有答案了 我收到以下错误 实体框架提供程序类型的 实例 成员 Npgsql NpgsqlServices Npgsql 版本 2 0 14 2 文化 中性 PublicKeyToken 5d8b90d52f46fda7 没

随机推荐

  • 查看php已安装扩展命令

    php m
  • 模型训练时间计算

    一 时间戳计算 记录当前时间 或者用 time perf counter 精度更高 import time t0 time time t0 time perf counter 记录结束时间 t1 time time t1 time perf
  • C# winform使用StreamWriter的方式将dataTable导出到Excel

    代码笔记 public void Export2Excel if this GridView logData Rows Count gt 0 SaveFileDialog saveFileDialog new SaveFileDialog
  • 【HAL库】STM32F103输出固定数量的PWM波形

    目的 用STM32F103ZET6的TIM1 CH1输出10个脉冲 实现方法主要有两种 一种用中断计数 一种用主从定时器门控方式 一 中断计数 首选需要选择合适的IO口 我选的是PE9 对应TIM1 CH1 然后在STM32CUBEMX里面
  • C++继承和多态特性

    文章目录 前言 1 什么是面向对象的继承特性 2 C 继承中的权限管控 3 继承体系下子类和父类的关系 4 派生类和基类的构造析构关系 5 派生类和基类的同名成员问题 6 子类和父类的类型兼容规则 7 继承的优势与不良继承 8 组合介绍以及
  • windows10家庭版远程桌面连接报错:CredSSP加密oracle修正

    原地址 https www cnblogs com lindajia p 9021082 html Windows10远程桌面连接 报错信息 网上找到方法 但是奈何是 Win10家庭版 不能使用这个办法 具体操作可以看最后的引用链接 策略路
  • 【应急响应】后门攻击检测指南&Rookit&内存马&权限维持&WIN&Linux

    文章目录 Windows实验 常规后门 网络对外连接查看 自启动测试 隐藏账户 映像劫持 屏保 登录 Linux实验 常规后门 Rootkit后门 GScan rkhunter 权限维持后门 GScan rkhunter Web层面 通用系
  • 秋叶大神的Stable Diffusion整合包

    前段时间在研究Stable Diffusion本地化部署 但是对于新手小白来说算是比较难得 不过没关系 我在B站发现了秋叶大神的Stable Diffusion整合包 我在用很方便 必须分享出来 Stable Diffusion整合包下载地
  • 基于vue的页面加载动画

    基本原理是 在window加载之前 渲染出加载动画 页面渲染完成后 移除加载动画即可 在vue项目中一般只需二步 第一步 写css和dom 在vue项目的index html中引入css 第二步 在app vue created中移除加载动
  • pytorch_lighting

    1 pytorch lighting 简介 1 1 pytorch lighting 是什么 1 1 1 pytorch lightning 是什么 PyTorch Lightning 是一个开源的 PyTorch 加速框架 它旨在帮助研究
  • vue+Element-ui实现树形组件、表格树

    需求 要做出如下图所示的 树形表格 也就是数据之间有父子类关系的这种 可以点击展开 收缩 像上图这样的表格树 实现 1 使用树形组件 在学习树形表格之前 肯定得先搞懂普通的树形组件是怎么搞的 然后将其套到表格中就好了 请参考ElementU
  • linux real时间,【整理】RT-linux 实时Linux RealTime Linux

    折腾 整理 数控系统 操作系统 期间 看提到了RT linux 去研究看看 RT linux Vanilla kernel的问题 Linux kernel在spinlock irq上下文方面无法抢占 因此高优先级任务被唤醒到得以执行的时间并
  • 力扣刷题:两数相加

    给你两个 非空 的链表 表示两个非负的整数 它们每位数字都是按照 逆序 的方式存储的 并且每个节点只能存储 一位 数字 请你将两个数相加 并以相同形式返回一个表示和的链表 你可以假设除了数字 0 之外 这两个数都不会以 0 开头 输入 l1
  • Android Studio Proxy Setting 设置(详细图文说明)

    Android Studio代理设置 Android Studio Proxy Setting 设置 在很多时候编译依赖的相关库文件都是需要墙出去的 所以我们得学会怎么翻 具体可以查查网上很多详细的攻略 这里只介绍墙完后Android St
  • 【深入理解C++】空类对象所占用的空间大小

    文章目录 1 须知 2 空类对象所占用的空间大小 3 一个类继承空类 4 空类作为另一个类的成员 1 须知 类本身是没有大小的 类的大小指的是类的对象所占的大小 如果用 sizeof 运算符对一个类型名操作 得到的是具有该类型实体的大小 2
  • 移植4- uboot之网卡驱动移植

    linux 中 网络分为许多层 网卡处理物理与DATA LINK层 linux驱动就是将DATALINK层的数据包送到TCP IP层进行处理 主要是通过struct net device这个结构 struct net device实现了支持
  • 字符串转化使用String.valueOf(value) 代替 “ “ + value

    文章目录 把其它对象或类型转化为字符串时 使用String valueOf value 比 value 的效率更高 把其它对象或类型转化为字符串反例 int num 520 value String strLove num 把其它对象或类型
  • 2023年超全前端面试题-背完稳稳拿offer(欢迎补充)

    HTML CSS相关 HTML5 HTML5新特性 增强了表单 input新增了一些type color 定义调色板 tel 定义包含电话号码的输入域 email 定义包含email地址的输入域 search 定义搜索域 number 定义
  • innodb索引概念

    author skate time 2013 04 09 总结记录下innodb的索引概念 以备查看 innodb索引分类 聚簇索引 clustered index 1 有主键时 根据主键创建聚簇索引 2 没有主键时 会用一个唯一且不为空的
  • Qt+Pyhton实现麒麟V10系统下word文档读写功能

    目录 前言 1 C 调用python 1 1 安装Python开发环境 1 2 修改Qt工程配置 1 3 初始化Python环境 1 4 C 调用Python 函数 1 5 常用的Python接口 2 python虚拟环境 2 1Pytho