五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

C++(Qt) 和 Word 交互總結(jié)(二)

2022-09-13 22:34 作者:devstone  | 我要投稿

閱讀本文大概需要 6 分鐘

之前有一篇文章介紹過 C++/Qt 操作 Word的一些方法,雖然能滿足一部分使用場(chǎng)景,但是終究是在某些平臺(tái)上有限制,使用起來還是不方便,所以就有了這邊文章

我們知道操作 Word其實(shí)還有一種方法,那就按照 OOXML規(guī)范讀寫即可,OOXML 是微軟 2007之后推出的一套標(biāo)準(zhǔn),凡是符合這個(gè)標(biāo)準(zhǔn)生成的文檔都可以正常打開,遺憾的是這方面 C++ 沒有可用的庫,一是因?yàn)楸旧?C++人群少,二是是用 C++ 實(shí)現(xiàn)工作量大,所以就只能選擇現(xiàn)有成熟的輪子

Python有非常多的開源庫可以使用,其中有一個(gè)Python-docx庫,完美實(shí)現(xiàn)了Word讀寫,使用 C++ 調(diào)用 Python是非常方便的,所以可以間接來實(shí)現(xiàn) Word的交互

支持功能:

  • 支持自定義標(biāo)題,包括樣式、字體、對(duì)齊方式、標(biāo)題級(jí)別等;

  • 支持插入任意行列表格,表格支持單獨(dú)設(shè)置某個(gè)單元格樣式,字體、顏色、是否加粗、水平、垂直對(duì)齊方式等;

  • 支持合并任意單元格;

  • 支持插入圖片,支持相對(duì)路徑和絕對(duì)路徑

下面看測(cè)試導(dǎo)出的效果:


我們知道 C/C++/Qt都是編譯型語言,也是是說不能直接從源碼運(yùn)行,而Python是解釋型語言,不需要經(jīng)過編譯成二進(jìn)制代碼可以直接從源碼運(yùn)行,在運(yùn)行 Python的時(shí)候首先經(jīng)過 Python 解釋器解釋,你可以理解成翻譯的意思,解釋成字節(jié)碼,然后在一條一條字節(jié)碼指令開始執(zhí)行

Python提供了一些C庫,我們可以在C/C++程序中包含對(duì)應(yīng)頭文件、庫文件,進(jìn)而調(diào)用函數(shù)方法來實(shí)現(xiàn)某個(gè)功能

調(diào)用 Python主要流程如下:

  • 初始化Python上下文環(huán)境(解釋器環(huán)境)

  • 導(dǎo)入對(duì)應(yīng)的模塊

  • 獲取對(duì)應(yīng)函數(shù)對(duì)象,參數(shù)轉(zhuǎn)換,調(diào)用函數(shù)

  • 解析返回值,結(jié)束調(diào)用

  • 釋放 python解釋器

C++根據(jù)實(shí)際業(yè)務(wù)生成對(duì)應(yīng)的JSON字符串,然后調(diào)用Python傳遞給對(duì)應(yīng)函數(shù),在Python函數(shù)中解析JSON字符串然后生成Word內(nèi)容

整個(gè)腳本實(shí)現(xiàn)庫以及對(duì)應(yīng) Example 都已經(jīng)開源,感興趣的朋友直接訪問即可

https://github.com/kevinlq/QtPythonDocx

環(huán)境配置

下載并安裝好Python相關(guān)庫,確保本地環(huán)境沒有問題,記得安裝好Python-docx庫??截?code>Python相關(guān)依賴庫到你的項(xiàng)目目錄,不如下面這樣

QtPythonDocx
|??3rdparty
│??└─Python310
│??????├─include
│??????│??├─cpython
│??????│??└─internal
│??????└─libs
├─bin
│??├─Python310
│??│??├─DLLs
│??│??└─Lib
|??|─script
│??│??wordOperate.py

關(guān)于一些版本事項(xiàng)、以及中間會(huì)遇到那些坑,文末有注意事項(xiàng)統(tǒng)一介紹

調(diào)用 Python

為了做到簡(jiǎn)潔、通用,我們編寫一個(gè)腳本調(diào)用類,該類和具體的業(yè)務(wù)無關(guān),只負(fù)責(zé)傳入不同模塊、函數(shù)、參數(shù)調(diào)用對(duì)應(yīng)的Python函數(shù)并能夠返回對(duì)應(yīng)的結(jié)果,這樣后續(xù)的調(diào)用者就使用的時(shí)候和使用普通函數(shù)沒有區(qū)別

為了實(shí)現(xiàn)這個(gè)目的,目前有幾個(gè)知識(shí)點(diǎn)需要解決:

  • 由于Python數(shù)據(jù)類型和C++不一樣,如果要通用那么就需要進(jìn)行轉(zhuǎn)換,怎么做到C++一個(gè)參數(shù)類型匹配Python多個(gè)類型?

  • 返回值處理,我們的業(yè)務(wù)函數(shù)返回值可能多種多樣,怎么兼容?

  • 編碼轉(zhuǎn)換,Python中支持UTF-8,我們程序處理中數(shù)據(jù)可能包含多種類型,怎么轉(zhuǎn)換

解決了上述問題,基本也就是完成了本次要寫的腳本加載類

腳本調(diào)用類實(shí)現(xiàn)

首先看下類型問題,其實(shí)我們這里需要一個(gè)萬能類型來作為函數(shù)入?yún)ⅲ敲从羞@個(gè)類型么?有,如果你的編譯器支持 C++17,那么可以用std::variant

std::variant<int,?double,?std::string>?inputArg

由于作者本人對(duì) Qt比較熟一點(diǎn),所以本次程序中使用了大量的Qt內(nèi)置數(shù)據(jù)類型,原理是相通的

KPythonRunScript 類的實(shí)現(xiàn),核心函數(shù)如下所示

bool?callFun(const?char?*funcName,
?????????????????const?QVariantList?&args?=?QVariantList(),
?????????????????QVariant?&returnValue?=?QVariant(QVariant::Invalid));

  • funcName: python 腳本中對(duì)應(yīng)的函數(shù)名字

  • args: 函數(shù)入?yún)ⅲ鶕?jù)實(shí)際腳本中函數(shù)參數(shù)個(gè)數(shù)而定

  • returnValue: 返回值,如果腳本函數(shù)有返回值初始化的時(shí)候賦予對(duì)應(yīng)類型

實(shí)際Python腳本中函數(shù)的入?yún)€(gè)數(shù)是不確定的,為了兼容多個(gè)調(diào)用場(chǎng)景,所以采用了數(shù)組作為實(shí)際的入?yún)?,?shù)組每個(gè)元素采用QVariant類型,這樣就能根據(jù)實(shí)際傳入的類型來判斷,在調(diào)用Python的時(shí)候應(yīng)該轉(zhuǎn)換為什么類型

返回值類型也一樣,初始化調(diào)用時(shí)確定好本次調(diào)用的返回值類型,這樣在Python腳本調(diào)用完成后才能把返回值轉(zhuǎn)為我們C++實(shí)際的返回值

類型轉(zhuǎn)換:

for(int?index?=?0;?index?<?args.size();?index++)
{
????QVariant?arg?=?args[index];
????switch?(arg.type())
????{
????case?QVariant::String:
????{
????QByteArray?baContent?=?arg.toString().toLocal8Bit();
????PyTuple_SetItem(pArgsObj,?index,?Py_BuildValue("s",?baContent.constData()));
????}
????break;
????case?QVariant::Int:?????????PyTuple_SetItem(pArgsObj,?index,?Py_BuildValue("i",?arg.toInt()));??????????????????????????????????????break;
????case?QVariant::Double:??????PyTuple_SetItem(pArgsObj,?index,?Py_BuildValue("d",?arg.toDouble()));???????????????????????????????????break;
????case?QVariant::LongLong:????PyTuple_SetItem(pArgsObj,?index,?Py_BuildValue("l",?arg.toLongLong()));?????????????????????????????????break;
????case?QVariant::Char:????????PyTuple_SetItem(pArgsObj,?index,?Py_BuildValue("b",?arg.toChar().toLatin1()));??????????????????????????break;
????case?QVariant::Invalid:?????PyTuple_SetItem(pArgsObj,?index,?Py_BuildValue("()"));??????????????????????????????????????????????????break;
????default:?break;
????}
}

這里目前適配了上述幾種類型,如果后續(xù)不滿足繼續(xù)擴(kuò)展其它類型即可

Python腳本對(duì)應(yīng)的函數(shù)

def?generateWord(strContent):
????#...
????return?True

詳細(xì)調(diào)用

在上述實(shí)現(xiàn)的類的基礎(chǔ)上,調(diào)用其實(shí)就變的很簡(jiǎn)單了,就和我們調(diào)用本地某個(gè)函數(shù)一樣,非常輕松

KPythonRunScript?*pRunScript?=?KPythonRunScript::instance("wordOperate");
QVariant?returnValue?=?true;
QVariantList?args?=?{""};
bool?bResult?=?pRunScript->callFun("generateWord",?args,?returnValue);
qDebug()?<<?"run?generateWord?result:"?<<?bResult?<<?returnValue;

if(!bResult)
{
????qWarning()?<<?"write?word?fail.....";
????return;
}

可能你注意到程序中使用了單例,為什么使用單例?這是因?yàn)閱蝹€(gè)進(jìn)程Python解釋器相關(guān)內(nèi)容初始化一次即可,后續(xù)隨意調(diào)用不用再次初始化,實(shí)際驗(yàn)證中也證實(shí)了,多次初始化會(huì)有一些異常問題(雖然每次用完已經(jīng)釋放了,再次初始化還是會(huì)有問題)

這樣就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的調(diào)用過程,具體Python文件中的內(nèi)容可以看我開源的工程目錄中的內(nèi)容,其實(shí)就是把各種操作Word方法封裝成函數(shù)了,擴(kuò)展了常用的字段

QtPythonDocx/bin/script/wordOperate.py

JSON格式說明

由于 Word 內(nèi)容較多,調(diào)用時(shí)兼容很多寫入場(chǎng)景,因此目前設(shè)計(jì)使用 JSON 格式來交互,基本覆蓋大部分使用場(chǎng)景,而且支持各種自定義,完全滿足日常使用,下面是各個(gè)字段的說明

全局配置

  • savePath: 定義了生成的 Word 文檔路徑,確保該路徑有寫入權(quán)限,否則可能會(huì)失敗

  • openFile: 導(dǎo)入成功后是否打開該文檔

  • line_spacing: 行間距,默認(rèn)給 1.5倍

  • header: 頁眉文本,不需要頁眉直接給空即可

  • footer: 頁腳文本

  • content:[] 這里是 Word 內(nèi)容部分,采用數(shù)組存儲(chǔ),由于數(shù)組有有序的,因此嚴(yán)格按照你的內(nèi)容順序依次傳入即可

  • fontSize: 全局字體大小

  • fontName: 全局字體名字,設(shè)置后后續(xù)每個(gè)正文、標(biāo)題、表格等可以不用設(shè)置,全局統(tǒng)一

正文

下面是正文內(nèi)容部分說明

  • type: 標(biāo)識(shí)是那種類型,0:標(biāo)題,1: 普通文本,2:圖片,3:表格,其它類型后續(xù)擴(kuò)展自定義

  • text: 如果是文本或者標(biāo)題給定內(nèi)容

  • level: 級(jí)別,目前只有標(biāo)題類型生效

  • bold: 是否加粗

  • italic: 是否傾斜

  • strike: 是否刪除線

  • alignment: 對(duì)齊方式,主要有這么幾種:left, right,center

  • color: 對(duì)應(yīng)文本的顏色

  • height: 行高

插入表格

如果是表格,那么有這些擴(kuò)展字段

  • columns: 列數(shù)

  • rows: 行數(shù)

  • height: 行高,所有行設(shè)置一樣的行高,也可以自定義每行的行高

  • mergeCells: 要合并的單元格數(shù)組,比如合并 (0,0)和(0,1)單元格,那么內(nèi)容如下

{"begin":?[0,0],?"end":?[0,1]}

  • tableCell: 單元格內(nèi)容,依次填充每個(gè)單元格內(nèi)容即可,每個(gè)單元格內(nèi)容和普通文本類似,下面是一個(gè)示例

tableCell":?[
????????????????{"text":?"我是第一個(gè)單元格,加粗,傾斜,紅色",?"style":?"",?"bold":?true,?"italic":?true,"color":?"#ff0000","alignment":?"center"},
????????????????{"text":?"00和01合并了,02會(huì)覆蓋01的值,加粗變紅,左對(duì)齊",?"style":?"",?"bold":?true,?"italic":?false,"color":?"#ff0000","alignment":?"left"},
????????????????{"text":?"03",?"style":?"",?"bold":?false,?"italic":?false,"color":?"#000000","alignment":?"center"},
????????????????{"text":?"04",?"style":?"",?"bold":?false,?"italic":?false,"color":?"#000000","alignment":?"center"},
????????????????{"text":?"05",?"style":?"",?"bold":?false,?"italic":?false,"color":?"#000000","alignment":?"center"},
????????????????{"text":?"06",?"style":?"",?"bold":?false,?"italic":?false,"color":?"#000000","alignment":?"center"},
????????????????{"text":?"07",?"style":?"",?"bold":?false,?"italic":?false,"color":?"#000000","alignment":?"center"},
????????????????{"text":?"08",?"style":?"",?"bold":?false,?"italic":?false,"color":?"#000000","alignment":?"center"}
????????????]

插入圖片

圖片字段和其它文本字段類似,額外添加圖片路徑屬性即可

  • picture: "./test.png"

注意圖片路徑支持相對(duì)路徑和絕對(duì)路徑,根據(jù)自己實(shí)際需要傳遞即可

總結(jié)

本次通過Python的方式可以很好的支持很多之前出現(xiàn)的異常問題,足以滿足我們遇到的各種業(yè)務(wù)需要導(dǎo)出生成Word難題,而且導(dǎo)出速度非???,實(shí)際測(cè)試生成 10 頁左右文檔耗時(shí)不到 2秒,測(cè)試了多臺(tái)電腦,實(shí)際效果都非常理想

注意事項(xiàng)

  • Python版本選擇問題,確保你的程序最終要運(yùn)行的平臺(tái),如果要最低要求是Windows7,那么建議選擇 Python3.8版本即可,如果無所謂那么選擇最新穩(wěn)定版本即可;

  • Python 注意選擇和你程序使用同一個(gè)位數(shù),程序編譯器使用的是 64 位,那就下載 64 位,32位同理 ;

推薦閱讀


C++(Qt) 和 Word 交互總結(jié)(二)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國家法律
六安市| 云南省| 普安县| 斗六市| 米脂县| 即墨市| 嘉鱼县| 凤城市| 仙游县| 嵊州市| 大洼县| 大余县| 镇江市| 专栏| 西城区| 乌拉特前旗| 东安县| 都昌县| 闻喜县| 天镇县| 新巴尔虎右旗| 沂南县| 新丰县| 璧山县| 大方县| 榕江县| 上杭县| 额尔古纳市| 天长市| 拜城县| 台北市| 南华县| 叙永县| 四会市| 阿图什市| 洪江市| 绥滨县| 永州市| 象山县| 凌云县| 徐州市|