在Qt中使用已有模板創建新Word文檔

在這篇帖子中我將詳細講述如何在Qt環境下使用已有Word模板文件創建新的文檔,並對模板文檔內容填充。目前,我只對替換文字和對錶格進行操作進行了介紹,如何在文檔插入圖片未在本文中提及。

開發環境

本文中使用的開發環境是Qt5.10.0。由於本文中的實現方式是通過COM組件操作Word,需要在.pro文件中添加QT += axcontainer,在Qt4的版本中與Qt5是有點區別的,在Qt4中添加CONFIG += qaxcontainer。

從代碼中看過程

多餘的就不說了,具體過程看註釋吧。

WordEngine.h

#ifndef WORDENGINE_H
#define WORDENGINE_H

#include <QObject>
#include <QAxObject>
#include <QAxWidget>

class WordEngine : public QObject
{
    Q_OBJECT
public:
    explicit WordEngine(QObject *parent = 0);

public slots:
    bool open(const QString &file);//打開文檔
    void save(const QString &savePath);//保存並關閉文檔

    void replaceText(const QString &label,const QString &text);//替換文檔中標籤出的文字
    void alterTableRowCount(const QString &tabel, const int rowCount);//在表箇中添加新行
    void fillTableCell(const QString &tabel,const QList<QStringList> &data);//填充表格內容

private:
    QAxWidget *_word;//word主程序
    QAxObject *_workDocument;//工作簿
    bool _isOpen;//文檔打開狀態

    QMap<QString,int> _tabelIndex;//文檔中的表格索引,注意word中表格的索引值是從1開始的,這裏根據不同的情況單獨實現
};

#endif // WORDENGINE_H

WordEngine.cpp

#include "WordEngine.h"
#include "qt_windows.h"
#include <QMessageBox>

WordEngine::WordEngine(QObject *parent) : QObject(parent)
{
    _word = NULL;
    _workDocument = NULL;
    _isOpen = false;

    /// 初始化表格索引,在word中可以直接獲取表格的索引而不是書籤來編輯表格內容,
    /// 所以,這裏的索引是需要用戶手動進行維護的
    _tabelIndex["table1"] = 1;
    _tabelIndex["table2"] = 2;
}

/// Summary:根據傳入的模板文件地址創建新的word文檔並打開
/// parameters:
///     file:.dot模板文件的絕對地址,這裏只能使用絕對地址,否則找不到文件,並且建議使用QDir::toNativeSeparators()將地址中的'/'轉換成'\'
/// return:
///     文檔是否打開
bool WordEngine::open(const QString& file)
{
    _word = new QAxWidget("word.Application");
    QAxObject *document = _word->querySubObject("Documents");//獲取所有打開的文檔
    if (!document)
        return false;

    document->dynamicCall("Add(QString)",file);//使用模板文件創建新的文檔
    _workDocument = _word->querySubObject("ActiveDocument");//激活文檔

    if (_workDocument)
        _isOpen = true;
    else
        _isOpen = false;

    if (!_isOpen)
    {
        QMessageBox box(QMessageBox::Information,QString("提示"),QString("未找到模板文件:%0").arg(file));
        box.addButton(QString("確定"),QMessageBox::AcceptRole);
        box.exec();
    }

    return _isOpen;
}

/// Summary:將文檔保存到指定地址,並關閉word程序
/// parameters:
///     savePath:word的保存地址
void WordEngine::save(const QString &savePath)
{
    //保存
    if (_isOpen && _workDocument)
    {
        _workDocument->dynamicCall("SaveAs (const QString&)",savePath);
    }

    if (_word)
    {
        _word->setProperty("DisplayAlerts",true);
    }

    //關閉文檔
    if (_workDocument)
    {
        _workDocument->dynamicCall("Close(bool)",true);
        delete _workDocument;
        _workDocument = NULL;
    }

    //推出word程序
    if (_word)
    {
        _word->dynamicCall("Quit()");
        delete _word;
        _word = NULL;
    }

    _isOpen = false;
}

/// Summary:替換指定書籤處的內容
/// parameters:
///     label:書籤名稱,這裏的書籤對應的是在word中的插入->書籤
///     text:內容
void WordEngine::replaceText(const QString &label, const QString &text)
{
    if (!_workDocument)
        return ;

    //查找書籤
    QAxObject *bookmark = _workDocument->querySubObject("Bookmarks(QString)",label);
    if (bookmark)
    {
        //選定書籤,並替換內容
        bookmark->dynamicCall("Select(void)");
        bookmark->querySubObject("Range")->setProperty("Text",text);
        delete bookmark;
    }
}

/// Summary:調整表格行數,目前只能插入不能刪除,在word模板中,在表格中至少需要有一行內容空行,否則在插入新行的時候,數據內容會跟隨表頭行的格式,有時候導出結果會非常難看
/// parameters:
///     tabel:表格名稱
///     rowCount:行數
void WordEngine::alterTableRowCount(const QString &tabel, const int rowCount)
{
    if (NULL == _workDocument) return;
    QAxObject *table = _workDocument->querySubObject("Tables(int)",_tabelIndex.value(tabel));//獲取表格
    if (NULL == table) return;

    //獲取表格目前的行數
    QAxObject *rows = table->querySubObject("Rows");
    qint32 count = rows->dynamicCall("Count").toInt();

    //插入行
    for (int i = count - 1; i < rowCount; ++i)
    {
        rows->querySubObject("Add()");
    }
}

/// Summary:填充表格內容
/// parameters:
///     tabel:表格名稱
///     data:內容
void WordEngine::fillTableCell(const QString &tabel, const QList<QStringList> &data)
{
    if (NULL == _workDocument) return;
    QAxObject *table = _workDocument->querySubObject("Tables(int)",_tabelIndex.value(tabel));//獲取表格
    if (NULL == table) return;

    //獲取表格目前的行數
    QAxObject *rows = table->querySubObject("Rows");
    qint32 rowCount = rows->dynamicCall("Count").toInt();

    //獲取表格目前的列數
    QAxObject *columns = table->querySubObject("Columns");
    qint32 columnCount = columns->dynamicCall("Count").toInt();

    //當前表格行數小於數據的行數,調整到數據的行數
    if (data.size()>rowCount)
    {
        alterTableRowCount(tabel,data.size());
    }

    //填充表格內容
    for (int row = 0; row < data.size(); ++row)
    {
        for (int column = 0; column < data.at(row).size() && column < columnCount; ++column)
        {
            QAxObject *cell=table->querySubObject("Cell(int,int)",row+2,column+1);//獲取單元格,注意word中的索引是從1開始的,再加上表頭row應該+2
            if(!cell) return;
            cell->dynamicCall("Select(void)");
            cell->querySubObject("Range")->setProperty("Text",data.at(row).at(column));
            delete cell;
        }
    }
}                       

不足之處

這種方法讀寫文檔的效率非常低,但是在Qt中Qwidget的派生類都無法在子線程中運行,所以當文件內容比較多的時候我們能做的只有等……或許你有更好的方法,請一定告訴我(_ _)。゜zzZ

以上就是如何在Qt中創建Word文檔並修改word文檔內容。如有不明白的地方歡迎留言或通過下面的郵件地址交流,若帖子中有錯誤的地方同樣歡迎留言批評指正,在此謝過路過的各位大神。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章