简介
- 本文主要介绍QAxObject类导出为word文件操作。以实现导出一份成绩单为例,介绍可能会出现的问题,如何去解决。同时会将word中常用的一些属性枚举封装为函数进行介绍,方便读者理解。
代码实现
- 代码分析详见注释
- custome_output_file_service.h
#pragma once
#include <QObject>
#include <QAxObject>
#include <QTextCodec>
#include <QDateTime>
#include <QDebug>
#include "custome_output_file_global.h"
class CustomeOutputFileService
:public ICustomeOutputFile
{
public:
CustomeOutputFileService();
~CustomeOutputFileService();
virtual bool CreateRecordWord(CyCString _path);
virtual bool SetRecordInformation(CyCString _name, int _count);
virtual bool InsertRecordData(vector<std::string> _data);
virtual bool Close();
private:
QAxObject * word_;
QAxObject * act_doc_;
QString file_path_;
int count_;
QAxObject* simulation_table_;
};
- custome_output_file_service.cpp
#include "custome_output_file_service.h"
#include "qt_windows.h"
CustomeOutputFileService::CustomeOutputFileService()
:count_(2)
{
}
CustomeOutputFileService::~CustomeOutputFileService()
{
}
bool CustomeOutputFileService::CreateRecordWord(CyCString _path)
{
file_path_ = StdString2QString(_path);
count_ = 2;
//因为COM是在GUI线程初始化和销毁的,在新开的线程里面并没有初始化,所以得自己初始化。
HRESULT r_com = OleInitialize(0);
if (r_com != S_OK && r_com != S_FALSE)
{
qDebug("Qt: Could not initialize OLE (error %x)",(unsigned int)r_com);
}
//创建word文档
//指向整个word应用程序
word_ = new QAxObject();
if (!word_->setControl("word.Application"))
return false;
word_->setProperty("Visible", false);
QAxObject *documents = word_->querySubObject("Documents");
if (!documents)
return false;
documents->dynamicCall("Add(void)");
//获取当前激活的文档
act_doc_ = word_->querySubObject("ActiveDocument");
if (act_doc_ == nullptr)
return false;
QAxObject* selection = word_->querySubObject("Selection");
selection->querySubObject("Font")->setProperty("Size", 11);
selection->dynamicCall("TypeText(const QString&)", "");
return true;
}
bool CustomeOutputFileService::SetRecordInformation(CyCString _name, int _count)
{
//当前日期
QDateTime cur_data_time = QDateTime::currentDateTime();
QString data_time = cur_data_time.toString("yyyy-MM-dd hh:mm:ss");
//设置标题风格及内容
QAxObject* selection = word_->querySubObject("Selection");
selection->querySubObject("Font")->setProperty("Size", 14);
selection->querySubObject("Font")->setProperty("Bold", true);
selection->querySubObject("ParagraphFormat")->setProperty("Alignment", "wdAlignParagraphCenter");
selection->dynamicCall("TypeText(const QString&)", QStringLiteral("成绩单\n"));
//设置成绩单信息风格及内容
selection->querySubObject("Font")->setProperty("Size", 11);
selection->querySubObject("Font")->setProperty("Bold", false);
selection->querySubObject("ParagraphFormat")->setProperty("Alignment", "wdAlignParagraphLeft");
selection->dynamicCall("TypeText(const QString&)", QStringLiteral("教师:%1 日期:%2\n").arg(StdString2QString(_name)).arg(data_time));
//设置数据内容格式
QAxObject* tables = act_doc_->querySubObject("Tables");
QAxObject* range = selection->querySubObject("Range");
simulation_table_ = tables->querySubObject("Add(QAxObject*, int, int)", range->asVariant(), _count + 1, 6);
QAxObject* border_line1 = simulation_table_->querySubObject("Borders(1)");
border_line1->dynamicCall("SetLineStyle(int)", 1);
QAxObject* border_line2 = simulation_table_->querySubObject("Borders(2)");
border_line2->dynamicCall("SetLineStyle(int)", 1);
QAxObject* border_line3 = simulation_table_->querySubObject("Borders(3)");
border_line3->dynamicCall("SetLineStyle(int)", 1);
QAxObject* border_line4 = simulation_table_->querySubObject("Borders(4)");
border_line4->dynamicCall("SetLineStyle(int)", 1);
QAxObject* border_line5 = simulation_table_->querySubObject("Borders(5)");
border_line5->dynamicCall("SetLineStyle(int)", 1);
QAxObject* border_line6 = simulation_table_->querySubObject("Borders(6)");
border_line6->dynamicCall("SetLineStyle(int)", 1);
QAxObject* trange = simulation_table_->querySubObject("Range");
trange->querySubObject("ParagraphFormat")->setProperty("Alignment", "wdAlignParagraphCenter");
trange->querySubObject("Cells")->setProperty("VerticalAlignment", "wdCellAlignVerticalCenter");
selection->querySubObject("Font")->setProperty("Bold", true);
simulation_table_->querySubObject("Cell(int, int)", 1, 1)->querySubObject("Range")->dynamicCall("SetText(QString)", QStringLiteral("姓名"));
simulation_table_->querySubObject("Cell(int, int)", 1, 2)->querySubObject("Range")->dynamicCall("SetText(QString)", QStringLiteral("学号"));
simulation_table_->querySubObject("Cell(int, int)", 1, 3)->querySubObject("Range")->dynamicCall("SetText(QString)", QStringLiteral("班级"));
simulation_table_->querySubObject("Cell(int, int)", 1, 4)->querySubObject("Range")->dynamicCall("SetText(QString)", QStringLiteral("实验场次"));
simulation_table_->querySubObject("Cell(int, int)", 1, 5)->querySubObject("Range")->dynamicCall("SetText(QString)", QStringLiteral("成绩"));
simulation_table_->querySubObject("Cell(int, int)", 1, 6)->querySubObject("Range")->dynamicCall("SetText(QString)", QStringLiteral("评语"));
return true;
}
//插入数据
bool CustomeOutputFileService::InsertRecordData(vector<std::string> _data)
{
if (_data.size() == 0)
{
return false;
}
for (int i = 0; i < _data.size(); ++i)
{
simulation_table_->dynamicCall("AutoFitBehavior(int)", 6);
simulation_table_->querySubObject("Rows(int)", count_)->setProperty("Height", 20);
simulation_table_->querySubObject("Cell(int, int)", count_, i + 1)->querySubObject("Range")->dynamicCall("SetText(QString)", StdString2QString(_data.at(i)));
}
count_++;
return true;
}
//关闭连接
bool CustomeOutputFileService::Close()
{
act_doc_->dynamicCall("SaveAs (const QString&)", file_path_);
act_doc_->dynamicCall("Close(bool)", true);
word_->dynamicCall("Quit()");
//关闭COM
OleUninitialize();
return true;
}
常见问题解决
1、QAxObject对象在子线程中连接失败
word_->setControl("word.Application")
- 连接对象为QAxWidget类对象,GUI相关对象不能在子线程中进行操作,所以应该修改为QAxObject类对象。
- 如果对象为QAxObject类对象还是连接失败,则查看COM是否在子线程初始化,如果没有添加如下代码
//因为COM是在GUI线程初始化和销毁的,在新开的线程里面并没有初始化,所以得自己初始化。
HRESULT r_com = OleInitialize(0);
if (r_com != S_OK && r_com != S_FALSE)
{
qDebug("Qt: Could not initialize OLE (error %x)",(unsigned int)r_com);
}
2、添加QAxObject头文件后编译报错:“无法打开源文件”
- 原因在于当前工程中并没有包含相应的模块,需要到项目属性设置中添加相应模块,并添加相应附加包含目录和附加依赖项。如下图所示:
3、修改单元格属性后未生效
- 查看设置单元格为全局还是特定单元格。
- 是否设置属性后再插入数据。
- 属性字段是否正确。
- 单元格对象是否添加。
常见属性
- 以下是一些word中表格常用的一些属性( QAxObject* selection_ = m_pWord->querySubObject(“Selection”);)
/*
* 排版方式
* 纵行、横行
*/
selection_->querySubObject("PageSetup")->setProperty("Orientation","wdOrientLandscape"); //纵
selection_->querySubObject("PageSetup")->setProperty("Orientation","wdOrientPortrait"); //横
/*
* 获取页宽
*/
int width_;
width_ = selection_->querySubObject("PageSetup")->property("PageWidth").toInt();;
/*
*设置字号
*/
selection_->querySubObject("Font")->setProperty("Size",14);
/*
*设置对齐方式
*/
selection_->querySubObject("ParagraphFormat")->setProperty("Alignment","wdAlignParagraphCenter"); //居中对齐
selection_->querySubObject("ParagraphFormat")->setProperty("Alignment","wdAlignParagraphJustify"); //分散对齐
selection_->querySubObject("ParagraphFormat")->setProperty("Alignment","wdAlignParagraphRight"); //右对齐
selection_->querySubObject("ParagraphFormat")->setProperty("Alignment","wdAlignParagraphLeft"); //左对齐
/*
*插入文字
*/
selection_->dynamicCall("TypeText(const QString&)","hello world!");
/*
*插入图片
*/
QString filename = file;
filename.replace("/","\\"); //转义字符替换
QAxObject *Inlineshapes = selection_->querySubObject("InlineShapes");
Inlineshapes->dynamicCall("AddPicture(const QString&)",filename);
delete Inlineshapes;
/*
*插入回车
*/
selection_->dynamicCall("TypeParagraph(void)");
/*
* 光标移到末尾,跳出单元格
*/
QVariantList params;
params.append(6);
params.append(0);
selection->dynamicCall("EndOf(QVariant&, QVariant&)", params).toInt();
/*
创建表格
QStringList headList 添加表头
*/
QAxObject* MainWindow::createTable(int row, int column, QStringList head_list)
{
QAxObject* selection = m_pWord->querySubObject("Selection");
if(!selection)
{
return false;
}
selection->dynamicCall("InsertAfter(QString&)", "\r\n");
QAxObject *range = selection->querySubObject("Range");
QAxObject *tables = m_pWorkDocument->querySubObject("Tables");
QAxObject *table = tables->querySubObject("Add(QVariant,int,int)",range->asVariant(),row,column);
table->setProperty("Style","网格型");
//表格自动拉伸列 0固定 1根据内容调整 2 根据窗口调整
table->dynamicCall("AutoFitBehavior(WdAutoFitBehavior)", 2);
//设置表头
for(int i=0;i<headList.size();i++)
{
table->querySubObject("Cell(int,int)",1,i+1)->querySubObject("Range")->dynamicCall("SetText(QString)", head_list.at(i));
//加粗
table->querySubObject("Cell(int,int)",1,i+1)->querySubObject("Range")->dynamicCall("SetBold(int)", true);
}
return table;
}
/*
填充表格
*/
void MainWindow::setCellText(QAxObject *table, int row, int column, QString text)
{
QAxObject* range = table->querySubObject("Cell(int, int)",row+1,column+1)->querySubObject("Range");
if( range)
return;
range->dynamicCall("SetText(QString)", text);
}
/*
表格插入图片
*/
void MainWindow::setAddPicture(QAxObject *table, int row, int column, QString picPath)
{
QAxObject* range = table->querySubObject("Cell(int, int)",row+1,column+1)->querySubObject("Range");
if(!range)
return;
range->querySubObject("InlineShapes")->dynamicCall("AddPicture(const QString&)",picPath);
}
/*
*光标跳转,类似表格中的tab
*/
selection->dynamicCall("MoveRight(int)",1);
以上是对QAxObject导出word文档表格的一些简单操作,新人第一次发博客,如果此文帮助到你( •̀ ω •́ )✧,动动小手点个赞可好O(∩_∩)O。
原创文章,转载请标明本文出处。