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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Qt5生成Word格式报告

發布時間:2023/12/14 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt5生成Word格式报告 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

引言

項目中需要生成word格式的報告文件,初探了Qt5通過word模板生成報告的方法,整理了使用時的環境配置、子線程中使用時的注意事項以及常用的操作方法,于此記錄。

環境:vs2012+Qt5.2+word2016

一、使用ActiveQt模塊

注意:ActiveQt只適用于windows平臺下,linux和macOS版本的Qt中是沒有這個庫的

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

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

#include <QAxWidget> #include <QAxObject>

二、子線程中使用

在使用過程中發現調用word過程比較耗時,會阻塞GUI線程,于是將保存報告操作移到子線程中.
不過在子線程中使用QAxWidget會報錯ASSERT failure in QWidget: "Widgets must be created in the GUI thread."這是由于線程里面不能創建GUI對象。
解決方案是用 QAxObjec取代QAxWidget,初始化過程如下:

bool Report::Open(QString Dir) {// 新建一個word應用程序,并設置為不可見//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打開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為模版新建一個文檔Documents->dynamicCall("Add(QString)", Dir);// 獲取當前激活的文檔m_Document = m_WordFile->querySubObject("ActiveDocument");if(NULL == m_Document){return false;}m_bInit = true;return true; }

同時由于在QApplication的主線程中,會自動初始化COM庫,而新開辟的子線程不會自動初始化COM庫,所以需要我們手動來初始化,方法如下:
添加頭文件:

#include <windows.h>

構造函數中初始化COM庫:

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方法產生線程this->moveToThread(&m_thread);m_thread.start(); }

析構函數中釋放:

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

三、準備word模板

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

四、代碼

1.插入書簽位置

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

2.批量插入

QString outFileName = QFileDialog::getSaveFileName(this, QStringLiteral("請輸入要保存的名字:"),".", "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("無法獲得Documents對象!"),QMessageBox::Ok);return ;}QStringList items;QStringList sometexts;//items按順序依次是“待匹配標簽名”和“插入的內容”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("無法獲取當前打開文件對象!"),QMessageBox::Ok);return;}QAxObject *allBookmarks = currentDoc->querySubObject("Bookmarks");if (!allBookmarks) {QMessageBox::warning(this, QStringLiteral("警告"), QStringLiteral("無法獲取模板中的書簽,請先插入書簽!"), QMessageBox::Ok);return ;}int count = allBookmarks->property("Count").toInt();/* 填寫模板中的書簽 */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,未找到匹配的書簽,提示輸入QString text = QInputDialog::getText(this, QStringLiteral("請輸入"), QStringLiteral("%1").arg(name));bookmark->querySubObject("Range")->setProperty("Text", text);itemList.append(name);itemList.append(text);}}//依次插入sometexts中內容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對象定位后插入表格

/******************************************************************************* 函數:intsertTable* 功能:創建表格* 參數:nStart 開始位置; nEnd 結束位置; 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", "網格型"); }

方法二:利用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");//設置標題 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; } }

插入表格,修改列寬等是后來看到的,可參考這個github項目中的WordEngine實現

五、其他

用以下方法往bookmark插入內容:

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

如果dot文件中并沒有這個bookmark,會報如下錯誤:

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

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

最后附上相關源碼:demo-Qt5生成Word格式報告(demo是最開始寫的,未包含插入表格,多線程等方法實現,比較簡單)

參考

Qt利用ActiveX生成Word文檔
qt中如何使用ActiveX讀寫word
github-試卷自動生成系統
github-QTScada
QT在子線程中使用QAxWidget需要初始化COM的問題

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。