日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Qt5生成Word格式报告

發(fā)布時(shí)間:2023/12/14 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt5生成Word格式报告 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

  • 引言
  • 一使用ActiveQt模塊
  • 二子線程中使用
  • 三準(zhǔn)備word模板
  • 四代碼
    • 插入書(shū)簽位置
    • 批量插入
    • 插入表格
      • 方法一利用Range對(duì)象定位后插入表格
      • 方法二利用bookmark定位后插入表格
  • 五其他
  • 參考

引言

項(xiàng)目中需要生成word格式的報(bào)告文件,初探了Qt5通過(guò)word模板生成報(bào)告的方法,整理了使用時(shí)的環(huán)境配置、子線程中使用時(shí)的注意事項(xiàng)以及常用的操作方法,于此記錄。

環(huán)境:vs2012+Qt5.2+word2016

一、使用ActiveQt模塊

注意:ActiveQt只適用于windows平臺(tái)下,linux和macOS版本的Qt中是沒(méi)有這個(gè)庫(kù)的

首先需要添加庫(kù)文件,可以直接在VS2012菜單欄Qt5->Qt Project Setting->勾選Active Qt

勾選之后再次查看Qt Project Setting,發(fā)現(xiàn)自動(dòng)勾上了Active Qt server,同時(shí)“項(xiàng)目屬性->配置屬性->鏈接器->輸入->附加依賴(lài)性”中自動(dòng)加入了Qt5AxContainerd.lib;Qt5AxBased.lib
此后便可成功include頭文件

#include <QAxWidget> #include <QAxObject>

二、子線程中使用

在使用過(guò)程中發(fā)現(xiàn)調(diào)用word過(guò)程比較耗時(shí),會(huì)阻塞GUI線程,于是將保存報(bào)告操作移到子線程中.
不過(guò)在子線程中使用QAxWidget會(huì)報(bào)錯(cuò)ASSERT failure in QWidget: "Widgets must be created in the GUI thread."這是由于線程里面不能創(chuàng)建GUI對(duì)象。
解決方案是用 QAxObjec取代QAxWidget,初始化過(guò)程如下:

bool Report::Open(QString Dir) {// 新建一個(gè)word應(yīng)用程序,并設(shè)置為不可見(jiàn)//m_WordFile = new QAxWidget("Word.Application", 0, Qt::MSWindowsOwnDC);m_WordFile = new QAxObject();//取代QAxWidget,使其在子線程中可用bool bFlag = m_WordFile->setControl( "word.Application" );if(NULL == m_WordFile){// 嘗試用wps打開(kāi)bFlag = m_WordFile->setControl( "kwps.Application" );if(!bFlag){return false;}}m_WordFile->setProperty("Visible", false);// 獲取所有的工作文檔QAxObject *Documents = m_WordFile->querySubObject("Documents");if(NULL == Documents){return false;}// 以文件template.dot為模版新建一個(gè)文檔Documents->dynamicCall("Add(QString)", Dir);// 獲取當(dāng)前激活的文檔m_Document = m_WordFile->querySubObject("ActiveDocument");if(NULL == m_Document){return false;}m_bInit = true;return true; }

同時(shí)由于在QApplication的主線程中,會(huì)自動(dòng)初始化COM庫(kù),而新開(kāi)辟的子線程不會(huì)自動(dòng)初始化COM庫(kù),所以需要我們手動(dòng)來(lái)初始化,方法如下:
添加頭文件:

#include <windows.h>

構(gòu)造函數(shù)中初始化COM庫(kù):

Report::Report(QObject *parent): QObject(parent) {HRESULT result = OleInitialize(0);if (result != S_OK && result != S_FALSE){qDebug()<<QString("Could not initialize OLE (error %x)").arg((unsigned int)result);}//moveToThread方法產(chǎn)生線程this->moveToThread(&m_thread);m_thread.start(); }

析構(gòu)函數(shù)中釋放:

Report::~Report() {OleUninitialize();m_thread.quit();m_thread.wait(); }

三、準(zhǔn)備word模板

在word文檔中手動(dòng)添加書(shū)簽(bookmark)后保存為dot格式

四、代碼

1.插入書(shū)簽位置

QString outFileName = QFileDialog::getSaveFileName(this, QStringLiteral("請(qǐng)輸入要保存的名字:"),".", "Microsoft Word 97-2003(*.doc);;Microsoft Word 2007-2013(*.docx)");if (outFileName.isEmpty()) {QMessageBox::warning(this, tr("警告"),tr("輸入的文件名為空!"),QMessageBox::Ok);return ;}// 新建一個(gè)word應(yīng)用程序,并設(shè)置為不可見(jiàn) QAxWidget *word=new QAxWidget("Word.Application", 0, Qt::MSWindowsOwnDC); word->setProperty("Visible", false); // 獲取所有的工作文檔 QAxObject * documents = word->querySubObject("Documents");// 以文件testTemplate.dot為模版新建一個(gè)文檔,注意這里的路徑為絕對(duì)路徑QDir dir(".");documents->dynamicCall("Add(QString)",QString("%1/testTemplate.dot").arg(dir.absolutePath())); // 獲取當(dāng)前激活的文檔 QAxObject *document=word->querySubObject("ActiveDocument"); // 獲取文檔中名字為T(mén)SName_1_1的標(biāo)簽 QString bookmakrName="TSName_1_1";QAxObject*bookmark_text=document->querySubObject(QString("Bookmarks(%1)").arg(bookmakrName).toLocal8Bit().data()); // 選中標(biāo)簽,將字符插入到標(biāo)簽位置 if(!bookmark_text->isNull()) { bookmark_text->dynamicCall("Select(void)"); bookmark_text->querySubObject("Range")->setProperty("Text",QStringLiteral("測(cè)試輸入")); } // 將文件另存為outFileName,關(guān)閉工作文檔,退出應(yīng)用程序 document->dynamicCall("SaveAs (const QString&)", outFileName); document->dynamicCall("Close (boolean)", true); //關(guān)閉文本窗口word->dynamicCall("Quit(void)"); //退出worddelete bookmark_text; delete document; delete documents; delete word;

2.批量插入

QString outFileName = QFileDialog::getSaveFileName(this, QStringLiteral("請(qǐng)輸入要保存的名字:"),".", "Microsoft Word 97-2003(*.doc);;Microsoft Word 2007-2013(*.docx)");if (outFileName.isEmpty()) {QMessageBox::warning(this, tr("警告"),tr("輸入的文件名為空!"),QMessageBox::Ok);return ;}word = new QAxWidget("Word.Application", 0, Qt::MSWindowsOwnDC);word->setProperty("Visible", false);word->setProperty("DisplayAlerts", true);QAxObject *docs = word->querySubObject("Documents");if (!docs) {QMessageBox::warning(this, tr("警告"), tr("無(wú)法獲得Documents對(duì)象!"),QMessageBox::Ok);return ;}QStringList items;QStringList sometexts;//items按順序依次是“待匹配標(biāo)簽名”和“插入的內(nèi)容”items<<"TSName_1_2"<<"TSName222"<<"TSName_1_1"<<"TSName111"<<"555";sometexts<<"111"<<"222"<<"333"<<"444"<<"555";editBookMarks(docs, sometexts, items, outFileName);word->dynamicCall("Quit(boolean)", true);delete word; void testword::editBookMarks(QAxObject *docs, QStringList sometexts, QStringList &itemList, QString outFileName) {QDir dir(".");docs->dynamicCall("Add(QString)", QString("%1/testTemplate.dot").arg(dir.absolutePath()));QAxObject *currentDoc = word->querySubObject("ActiveDocument");if(!currentDoc){QMessageBox::warning(this, QStringLiteral("警告"), QStringLiteral("無(wú)法獲取當(dāng)前打開(kāi)文件對(duì)象!"),QMessageBox::Ok);return;}QAxObject *allBookmarks = currentDoc->querySubObject("Bookmarks");if (!allBookmarks) {QMessageBox::warning(this, QStringLiteral("警告"), QStringLiteral("無(wú)法獲取模板中的書(shū)簽,請(qǐng)先插入書(shū)簽!"), QMessageBox::Ok);return ;}int count = allBookmarks->property("Count").toInt();/* 填寫(xiě)模板中的書(shū)簽 */for (int i = count; i > 0; --i) {QAxObject *bookmark = allBookmarks->querySubObject("Item(QVariant)", i);QString name= bookmark->property("Name").toString();int j=0;foreach(QString itemName , itemList){if (name == itemName) {QAxObject *curBM = currentDoc->querySubObject("Bookmarks(QString)", name);curBM->querySubObject("Range")->setProperty("Text", itemList.at(j+1));break;}j++;}if (j == itemList.length()) {//如果遍歷itemList,未找到匹配的書(shū)簽,提示輸入QString text = QInputDialog::getText(this, QStringLiteral("請(qǐng)輸入"), QStringLiteral("%1").arg(name));bookmark->querySubObject("Range")->setProperty("Text", text);itemList.append(name);itemList.append(text);}}//依次插入sometexts中內(nèi)容while(!sometexts.isEmpty()){QAxObject *currentRange = currentDoc->querySubObject("Range()");int rangeEnd = currentRange->property("End").toInt();currentRange->dynamicCall("setRange(QVariant, QVariant)", rangeEnd, rangeEnd);currentRange->dynamicCall("InsertAfter(QString)", QStringLiteral("\n%1-%3\n").arg(sometexts[0]).arg(1));sometexts.removeAt(0);}currentDoc->dynamicCall("SaveAs(QString&)", outFileName);currentDoc->dynamicCall("Close()"); }

效果如下:

3.插入表格

方法一:利用Range對(duì)象定位后插入表格

/******************************************************************************* 函數(shù):intsertTable* 功能:創(chuàng)建表格* 參數(shù):nStart 開(kāi)始位置; nEnd 結(jié)束位置; row hang; column 列* 返回值: void*****************************************************************************/ void WordEngine::intsertTable(int nStart, int nEnd, int row, int column) { QAxObject* ptst = m_wordDocuments->querySubObject( "Range( Long, Long )",nStart, nEnd );QAxObject* pTable = m_wordDocuments->querySubObject( "Tables" );QVariantList params;params.append(ptst->asVariant());params.append(row);params.append(column);if( pTable ){pTable->dynamicCall( "Add(QAxObject*, Long ,Long )",params);} // QAxObject* table = selection->querySubObject("Tables(1)"); // table->setProperty("Style", "網(wǎng)格型"); }

方法二:利用bookmark定位后插入表格

QAxObject *WordEngine::insertTable(QString sLabel, int row, int column) { QAxObject *bookmark = m_pWorkDocument->querySubObject("Bookmarks(QVariant)", sLabel); if(bookmark) { bookmark->dynamicCall("Select(void)"); QAxObject *selection = m_pWord->querySubObject("Selection"); selection->dynamicCall("InsertAfter(QString&)", "\n"); //selection->dynamicCall("MoveLeft(int)", 1); selection->querySubObject("ParagraphFormat")->dynamicCall("Alignment", "wdAlignParagraphCenter"); //selection->dynamicCall("TypeText(QString&)", "Table Test");//設(shè)置標(biāo)題 QAxObject *range = selection->querySubObject("Range"); QAxObject *tables = m_pWorkDocument->querySubObject("Tables"); QAxObject *table = tables->querySubObject("Add(QVariant,int,int)",range->asVariant(),row,column); for(int i=1;i<=6;i++) { QString str = QString("Borders(-%1)").arg(i); QAxObject *borders = table->querySubObject(str.toAscii().constData()); borders->dynamicCall("SetLineStyle(int)",1); } return table; } }

插入表格,修改列寬等是后來(lái)看到的,可參考這個(gè)github項(xiàng)目中的WordEngine實(shí)現(xiàn)

五、其他

用以下方法往bookmark插入內(nèi)容:

QString bookmakrName="TSName1_1_2";//假設(shè)dot文件中并沒(méi)有這個(gè)bookmarkQAxObject* bookmark_text=document->querySubObject("Bookmarks(const QString&)", bookmakrName); if(NULL == bookmark_text)//注意這個(gè)判斷不可少,否則下面調(diào)用isNull()時(shí)會(huì)出錯(cuò){return;}// 選中標(biāo)簽,將字符插入到標(biāo)簽位置 if(!bookmark_text->isNull()) //如果沒(méi)有匹配到對(duì)應(yīng)的bookmark,直接判斷會(huì)出錯(cuò),所以要提前返回{ bookmark_text->dynamicCall("Select(void)"); bookmark_text->querySubObject("Range")->setProperty("Text",QStringLiteral("測(cè)試輸入")); }

如果dot文件中并沒(méi)有這個(gè)bookmark,會(huì)報(bào)如下錯(cuò)誤:

QAxBase: Error calling IDispatch member Bookmarks: Exception thrown by serverCode : 5941Source : Microsoft WordDescription: ????????????Help : wdmain11.chm [25421]Connect to the exception(int,QString,QString,QString) signal to catch this exception

這時(shí)判斷NULL == bookmark_text返回即可,如果要避免匹配不存在的bookmark,可以在前面處理,比如上文“2.批量插入”中所示的先利用QAxObject *allBookmarks = currentDoc->querySubObject("Bookmarks");獲取所有Bookmarks,然后在進(jìn)行處理。

最后附上相關(guān)源碼:demo-Qt5生成Word格式報(bào)告(demo是最開(kāi)始寫(xiě)的,未包含插入表格,多線程等方法實(shí)現(xiàn),比較簡(jiǎn)單)

參考

Qt利用ActiveX生成Word文檔
qt中如何使用ActiveX讀寫(xiě)word
github-試卷自動(dòng)生成系統(tǒng)
github-QTScada
QT在子線程中使用QAxWidget需要初始化COM的問(wèn)題

總結(jié)

以上是生活随笔為你收集整理的Qt5生成Word格式报告的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。