Word版本:2010
实现功能:将类型设置为一级标题,将文档前三行先初始化为正文,再将第一行设置为标题2,然后形成目录的形式
调用:
WordMerger *m_pWordMerger = new WordMerger;
QString strSavePath = "D:/test/merger.doc";
QList<QVariant> listWord;
TestWord tag1;
tag1.m_strTypeName = "测试1";
tag1.m_strlstTestWordPath << "D:/test/word1.docx" << "D:/test/word2.docx" << "D:/test/word3.docx";
TestWord tag2;
tag2.m_strTypeName = "测试2";
tag2.m_strlstTestWordPath << "D:/test/word4.docx" << "D:/test/word5.docx" << "D:/test/word6.docx";
listWord.push_back(QVariant::fromValue(tag1));
listWord.push_back(QVariant::fromValue(tag2));
m_pWordMerger->setSavePath(strSavePath);
m_pWordMerger->mergeTestReports(listWord);
m_pWordMerger->startMerge();
progressbar.h
#ifndef PROGRESSBAR_H
#define PROGRESSBAR_H
#include <QDialog>
#include <QLabel>
#include <QProgressBar>
class ProgressBar : public QDialog
{
Q_OBJECT
public:
ProgressBar(QWidget *parent = 0);
~ProgressBar();
void initUI();
public slots:
void setProgressBarValue(double nValue);
void closeProgressBar();
private:
QLabel *m_pTipLabel;
QProgressBar *m_pProgressBar;
};
#endif // PROGRESSBAR_H
progressbar.cpp
#include "progressbar.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QSpacerItem>
ProgressBar::ProgressBar(QWidget *parent)
: QDialog(parent)
{
initUI();
setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint);
m_pProgressBar->setRange(0,100);
}
ProgressBar::~ProgressBar()
{
}
void ProgressBar::initUI()
{
this->resize(427,55);
QVBoxLayout *pVlayout = new QVBoxLayout;
QHBoxLayout *pHlayout = new QHBoxLayout;
m_pTipLabel = new QLabel("正在合并word文档,请稍等...");
m_pProgressBar = new QProgressBar;
pHlayout->addStretch();
pHlayout->addWidget(m_pTipLabel);
pHlayout->addStretch();
pVlayout->addLayout(pHlayout);
pVlayout->addWidget(m_pProgressBar);
this->setLayout(pVlayout);
}
void ProgressBar::setProgressBarValue( double nValue )
{
m_pProgressBar->setValue(qRound(nValue*100));
if (nValue == 1)
{
m_pTipLabel->setText("word文档合并完成!");
}
}
void ProgressBar::closeProgressBar()
{
close();
}
WordMerger.h
#ifndef WORDMERGER_H
#define WORDMERGER_H
#include <QObject>
#include <QVariant>
#include <QAxObject>
#include <QThread>
#include "WordOperator.h"
#include "ProgressBar.h"
struct TestWord {
QString m_strTypeName;
QStringList m_strlstTestWordPath;
};
Q_DECLARE_METATYPE(TestWord);
class WordMerger : public QObject
{
Q_OBJECT
public:
WordMerger();
~WordMerger();
void setSavePath(const QString &strSavePath);
void mergeTestReports(const QList<QVariant> &qListReports);
//查看测试报告是否生成成功,true:生成成功 false:没有生成
bool wordMergeSate();
//判断保存路径的文件夹是否存在,不存在则创建
bool judgeSaveDirIsExist(QString &strSaveDir);
void startMerge();
signals:
void sendProgressToBar(double);
void wordCloseFinish();
private:
QString m_strMergeSavePath;
QList<QVariant> m_qListWords;
//word总数,总共有几篇word
int m_nTotalWords;
//当前处理到哪篇word
int m_nCurrentWord;
ProgressBar *m_pProgressBar;
};
#endif //WORDMERGER_H
WordMerger.cpp
#include "WordMerger.h"
#include <QFileInfo>
#include <QApplication>
#include <QDebug>
#include <Ole2.h>
#include <QMessageBox>
#include <QDesktopServices>
#include <QUrl>
#include <QProcess>
#include <QDir>
#include <QCoreApplication>
WordMerger::WordMerger()
: m_strMergeSavePath("")
, m_nTotalWords(0)
, m_nCurrentWord(0)
, m_pProgressBar(NULL)
{
m_qListWords.clear();
m_pProgressBar = new ProgressBar;
m_pProgressBar->show();
connect(this,SIGNAL(sendProgressToBar(double)),m_pProgressBar,SLOT(setProgressBarValue(double)));
connect(this,SIGNAL(wordCloseFinish()),m_pProgressBar,SLOT(closeProgressBar()));
}
WordMerger::~WordMerger()
{
}
void WordMerger::setSavePath( const QString &strSavePath )
{
m_strMergeSavePath = strSavePath;
}
void WordMerger::mergeTestReports(const QList<QVariant> &qListReports)
{
m_qListWords = qListReports;
for (int i=0; i<m_qListWords.size(); ++i)
{
const QVariant &var = m_qListWords.at(i);
const TestWord &tag = var.value<TestWord>();
m_nTotalWords += tag.m_strlstTestWordPath.size();
}
}
void WordMerger::startMerge()
{
if (m_qListWords.isEmpty())
{
emit wordCloseFinish();
QMessageBox::information(NULL,"提示","测试报告列表为空!");
return;
}
QString strSaveDir = "";
if (!judgeSaveDirIsExist(strSaveDir))
{
emit wordCloseFinish();
QMessageBox::information(NULL,"提示",QString("文件夹%1不存在,创建也失败!").arg(strSaveDir));
return;
}
HRESULT result = OleInitialize(0);
//WordOperator创建和其函数使用必须在一个线程中 注:不可在主线程中创建,子线程中使用
WordOperator *m_pWordApp = new WordOperator;
if (!m_pWordApp->init()) //打开Word APP
{
emit wordCloseFinish();
OleUninitialize();
QMessageBox::information(NULL,"提示","Word初始化失败!");
return;
}
if (!m_pWordApp->createDocFromTemplate("")) //创建空白主文档
{
emit wordCloseFinish();
m_pWordApp->close();
OleUninitialize();
QMessageBox::information(NULL,"提示","创建主文档失败!");
return;
}
for (int i=0; i<m_qListWords.size(); ++i)
{
const TestWord &tag = m_qListWords.at(i).value<TestWord>();
//判断文件路径是否存在
foreach (const QString &strFileName, tag.m_strlstTestWordPath) {
if (!QFile::exists(strFileName))
{
QMessageBox::critical(NULL,"错误",QString("步骤报告<%1>不存在!").arg(strFileName));
m_pWordApp->close();
emit wordCloseFinish();
OleUninitialize();
return;
}
}
QString strMainTitle = QString("%1.%2").arg(i+1).arg(tag.m_strTypeName);
//例:SAC101,SAC102...为一级标题
m_pWordApp->insertTextToCurrentParagraph(strMainTitle,FIRST_LEVEL_TITLE);
for (int j=0; j<tag.m_strlstTestWordPath.size(); ++j)
{
const QString &strTestStepReportPath = tag.m_strlstTestWordPath.at(j);
QString strSubTitle = QString("%1.%2.").arg(i+1).arg(j+1);
m_pWordApp->copySubDocToMainDoc(strTestStepReportPath,strSubTitle);
++m_nCurrentWord;
emit sendProgressToBar((double)m_nCurrentWord/(double)m_nTotalWords);
}
}
m_pWordApp->save(m_strMergeSavePath);
m_pWordApp->close();
emit wordCloseFinish();
if (wordMergeSate())
{
if(QMessageBox::question(NULL, "提示", "生成报告成功。是否打开报告所在路径文件夹?", QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok)
{
//打开生成文件路径,并选中文件
QProcess process;
// 路径包含空格需要特殊处理
QString strTmpPath = QDir::toNativeSeparators(m_strMergeSavePath).replace(" ", "\" \"");
QString cmd = QString("explorer.exe /select,\"%1\"").arg(strTmpPath);
process.startDetached(cmd);
}
}
else
{
QMessageBox::information(NULL,"提示","测试报告生成失败!");
}
OleUninitialize();
}
bool WordMerger::wordMergeSate()
{
QFile file;
int nIndex = m_strMergeSavePath.lastIndexOf ("."); //从后面查找"."位置
if (nIndex == -1)
{
m_strMergeSavePath += ".docx";
}
if (file.exists(m_strMergeSavePath))
{
return true;
}
return false;
}
bool WordMerger::judgeSaveDirIsExist(QString &strSaveDir)
{
strSaveDir = QFileInfo(m_strMergeSavePath).absolutePath();
QDir dir;
if (!dir.exists(strSaveDir))
{
return dir.mkdir(strSaveDir);
}
return true;
}
WordOperator.h
#ifndef WORDOPERATOR__H
#define WORDOPERATOR__H
#include <QStringList>
#include <QMetaType>
#include <QObject>
#include "progressbar.h"
//一级标题
#define FIRST_LEVEL_TITLE -2
//二级标题
#define SECOND_LEVEL_TITLE -3
//正文
#define MAIN_BODY -67
class QAxObject;
class WordOperator :public QObject
{
Q_OBJECT
public:
WordOperator();
~WordOperator();
bool init();
bool createDocFromTemplate( const QString &file, bool visible = true );
void save(const QString &savePath);
void close();
//合并word函数 start...
//复制子文档到主文档
void copySubDocToMainDoc(const QString &strSubDocPath,const QString &strOrder);
void mergeTestReports(const QList<QVariant> &qListReports, const QString &strSavePath);
QAxObject *updateDocumentRange(); //更新主文档当前段落Range
void startMergeTestReports(const QList<QVariant> &qListReports, const QString &strSavePath);
void insertTextToCurrentParagraph(QString strText, int nLevel); //插入文本到当前段落
//合并word函数 end...
protected:
QAxObject * m_wordAxObj;
QAxObject * m_documentsAxObj;
QAxObject * m_documentAxObj;
QAxObject * m_documentRangeObj;
ProgressBar *m_ProgressBar;
QString m_strMergeSavePath; //合并word保存路径
};
#endif //WORDOPERATOR__H
WordOperator.cpp
#include <Ole2.h>
#include <QAxObject>
#include "WordOperator.h"
#include <QFileInfo>
#include <QClipboard>
#include <QApplication>
#include <QDebug>
#include <QThread>
#include <Windows.h>
static QAxObject * getItemFromArray(QAxObject * arrayObj, int index);
WordOperator::WordOperator()
:m_wordAxObj(0), m_documentsAxObj(0), m_documentAxObj(0)
,m_documentRangeObj(0),m_ProgressBar(0),m_strMergeSavePath("")
{
}
WordOperator::~WordOperator()
{
close();
}
bool WordOperator::init()
{
m_wordAxObj = new QAxObject("Word.Application");
if(!m_wordAxObj)
{
return false;
}
m_wordAxObj->setProperty("Visible", false);
m_documentsAxObj = m_wordAxObj->querySubObject("Documents");
if (!m_documentsAxObj)
{
return false;
}
return true;
}
bool WordOperator::createDocFromTemplate(const QString &file, bool visible)
{
if (m_wordAxObj == 0 || m_documentsAxObj == 0)
{
return false;
}
m_documentsAxObj->dynamicCall("Add(QString)", file);
m_documentAxObj = m_wordAxObj->querySubObject("ActiveDocument");
return m_documentAxObj != 0;
}
void WordOperator::save(const QString &savePath)
{
if (0 == m_documentAxObj)
{
return;
}
m_documentAxObj->dynamicCall("SaveAs2(const QString&)", savePath);
}
void WordOperator::close()
{
if (m_documentAxObj)
{
m_documentAxObj->dynamicCall("Close(bool)", false);
delete m_documentAxObj;
m_documentAxObj = nullptr;
}
if (m_wordAxObj)
{
m_wordAxObj->setProperty("DispalyAlerts", true);
QAxObject* axobjNormalTemplate = m_wordAxObj->querySubObject("NormalTemplate");
if(axobjNormalTemplate != nullptr)
{
axobjNormalTemplate->setProperty("Saved", true);
}
m_wordAxObj->dynamicCall("Quit()");
delete m_wordAxObj;
m_wordAxObj = nullptr;
}
}
void WordOperator:: mergeTestReports(const QList<QVariant> &qListReports, const QString &strSavePath)
{
m_ProgressBar = new ProgressBar(NULL);
connect(this,SIGNAL(sendProgressToBar(int)),m_ProgressBar,SLOT(setProgressBarValue(int)));
m_ProgressBar->show();
}
void WordOperator::startMergeTestReports( const QList<QVariant> &qListReports, const QString &strSavePath )
{
save(strSavePath);
}
QAxObject * WordOperator::updateDocumentRange()
{
if (!m_wordAxObj || !m_documentAxObj)
{
return NULL;
}
QAxObject *paragraphs = m_documentAxObj->querySubObject("Paragraphs");
int nParaCount = paragraphs->property("Count").toInt();
if (nParaCount <= 0)
{
return NULL;
}
QAxObject *paragraph = paragraphs->querySubObject("Item(int)",nParaCount);
if (!paragraph)
{
return NULL;
}
return paragraph->querySubObject("Range()");
}
void WordOperator::insertTextToCurrentParagraph(QString strText, int nLevel)
{
if (strText.isEmpty())
{
return;
}
m_documentRangeObj = updateDocumentRange();
if (!m_documentRangeObj)
{
return;
}
m_documentRangeObj->setProperty("Text",strText);
m_documentRangeObj->setProperty("Style",nLevel);
m_documentRangeObj->dynamicCall("InsertParagraphAfter()");
}
void WordOperator::copySubDocToMainDoc( const QString &strSubDocPath,const QString &strOrder)
{
m_documentsAxObj->dynamicCall("Add(QString)",strSubDocPath); //打开strDoc
QAxObject *pDocument = m_wordAxObj->querySubObject("ActiveDocument"); //获取当前激活文档
if (!pDocument)
{
return;
}
QAxObject *pRange = pDocument->querySubObject("Range()"); //获取strDoc文档中的所有内容,文档的Range代表该文档的所有内容
if (!pRange)
{
return;
}
QAxObject *pParagraphs = pRange->querySubObject("Paragraphs"); //获取到所有段落
if (!pParagraphs)
{
return;
}
int nParaCount = pParagraphs->property("Count").toInt();
if (nParaCount <= 0)
{
return;
}
//将前3段落设置为正文
for (int i=1; i<=2; ++i)
{
QAxObject *paragraph = pParagraphs->querySubObject("Item(int)",i);
if (!paragraph)
{
continue;
}
paragraph->setProperty("Style",MAIN_BODY);
}
QAxObject *paragraph = pParagraphs->querySubObject("Item(int)",1);
QAxObject *pParaRange = paragraph->querySubObject("Range()");
pParaRange->dynamicCall("InsertBefore(QString)",strOrder);
paragraph->setProperty("Style",SECOND_LEVEL_TITLE); //将第1段落设置为标题2
pRange->dynamicCall("Copy()"); //这里的复制是复制到剪贴板上的,所以复制和粘贴的对象可以不同
m_documentRangeObj = updateDocumentRange();
if (!m_documentRangeObj)
{
pDocument->dynamicCall("Close(boolean)",false);
return;
}
m_documentRangeObj->dynamicCall("Paste()"); //这里的复制是复制到剪贴板上的,所以复制和粘贴的对象可以不同
pDocument->dynamicCall("Close(int)",0); //0:不保存更改
}