操作Word文档
取得Word内容
上面通过Range的Copy方法,把Word文档的内容,放入了剪贴板中。此时,可以在其它支持剪贴板的应用中粘贴,比如粘贴到PowerPoint或者画图程序中,还可以在我们的Qt程序中,获取这种内容。
方法是通过QClipboard。
全局的QClipboard对象,可以通过QApplication来取得。
auto clipboard = QApplication::clipboard();
QClipboard类支持的主要只读方法有:
QImage image(QClipboard::Mode mode = Clipboard) const
QPixmap pixmap(QClipboard::Mode mode = Clipboard) const
QString text(QClipboard::Mode mode = Clipboard) const
QString text(QString &subtype, QClipboard::Mode mode = Clipboard) const
对于通过Range的Copy方法放入剪贴板的内容,通过text取出里面的文本,是最简单直观的方法。
另外,如果要保持Word文档的样式,还可以按照HTML格式取出,方法是使用QClipboard的mimeData()取得QMimeData(),之后调用QMimeData类的html方法。
如下代码,可以把Word文档指定页的内容,存成一个HTML文档。
bool
doc_to_html(QVarint doc, int pn, const QString &path)
{
auto pageRange = doc->querySubObject (
"GoTo(int, int, int, const QVariant&)", 1, 1, pn + 1);
auto endRange = doc->querySubObject ("GoTo(int, int, int, const QVariant&)",
1, 1, pn + 2);
if (pageRange && endRange)
{
int endPosition;
if (endRange->property ("Start").toInt () == 1)
{
auto content = doc->querySubObject ("Content");
endPosition = content->property ("End").toInt ();
delete content;
}
else
{
endPosition = endRange->property ("Start").toInt () - 1;
}
pageRange->setProperty ("End", endPosition);
pageRange->dynamicCall ("Copy()");
}
else
{
qWarning ("Failed to get page range\n");
return false;
}
auto clip = QApplication::clipboard ();
auto mime = clip->mimeData ();
auto qba = QByteArray::fromStdString (mime->html ().toStdString ());
QFile qfile(path);
qfile.open(QIODevice::WriteOnly);
qfile.write(qba);
qfile.close();
return true;
}
取得Word页面大小
通过Document对象的ActiveWindow的ActivePane,取得Page对象,Page对象的属性有Width、Height。
如:
void
wordPageSize (QVarint doc, int pn, int *x, int *y)
{
auto pnstr = QString ("Pages(%1)").arg (pn + 1);
auto win = doc->querySubObject ("ActiveWindow");
auto pane = win->querySubObject ("ActivePane");
auto page = pane->querySubObject (pnstr.toStdString ().c_str ());
auto width = page->property ("Width");
auto height = page->property ("Height");
if (x)
*x = width.toInt ();
if (y)
*y = height.toInt ();
}
在Qt中内嵌Word
前面提到的使用Word.Application对象,会打开一个单独的Word程序,尽管可以设置为不可见(Visible=false),但是毕竟不是在Qt的组件之中显示与交互。
而使用QAxWidget,直接打开一个Word进程的ActiveX控件,显示在我们的Qt程序中。
只是这时候,我们不能再使用Word.Application对象,而是使用Word.Document对象。
同时,也不能再使用Application.Documents的Open对象打开文档,而是使用QAxWidget的基类QAxObjectInterface的setControl方法。
根据官方文档,QAxWidget的setControl方法的原型为:
bool QAxObjectInterface::setControl(const QString &c)
Returns whether setting the COM object succeeded.
Sets the name of the COM object wrapped by this QAxBase object to c.`
而setControl,可以有几个功能:
效率最高的是设置注册过的组件UUID。
如:
ctrl->setControl(“{8E27C92B-1264-101C-8A2F-040224009C02}”);
第二快的是设置组件名称。
如:
ctrl->setControl(“MSCal.Calendar”);
最慢,但是最容易使用的是设置程序的全名:
如:
ctrl->setControl(“Calendar Control 9.0”);
还可以通过文件名。
如:
ctrl->setControl(“c:/files/file.doc”);
所以,我们如果只是在Qt程序中,调用Word(或者Excel、PowerPoint,但是使用的参数不同),则可以很简单地使用QAxObjectInterface的setControl方法,设置文档名。
如:
#include <QtAxContainer>
int
main (int argc, char *argv[])
{
QApplication app(argc, argv);
QString path = QString::fromLocal8Bit (argv[1]);
QAxWidget *doc_widget = new QAxWidget;
doc_widget->setVisible (true);
doc_widget->setControl (path);
app.exec();
}
上面这样创建出来的QAxWidget,即doc_widget,就是一个继承自QWidget的组件,可以做为普通的QWidget使用。
如果只是显示或者操作Word等Office文档,使用上面这种内嵌QAxWidget,是最简单的方法。
操作PowerPoint
PowerPoint应用的对象名叫做PowerPoint.Application,这一点与Word一样。
但是,当使用这个对象打开本地文档的时候,就完全不一样了。Word叫做Documents与Document,而PowerPoint叫做Presentations与Presentation。
所以,打开PowerPoint本地文档的过程是先打开PowerPoint.Application,然后打开Presentations,然后打开Presentation。而且,如前所述,Presentations没有OpenNoRepairDialog函数,只有Open。
打开PowerPoint文档
// 为演示方便,下述代码没有进行错误处理以及资源清理
QVariant
loadPPT (const QString &filename)
{
auto application = new QAxObject ("PowerPoint.Applicatoin");
application->setProperty ("Visible", false);
auto documents = application->querySubObject ("Presentations");
auto doc = documents->querySubObject (
"Open(const QString&)", filename);
return doc;
}
PowerPoint总页数
在PowerPoint中,页对应的对象叫Slide。
所以,取得一个PowerPoint文档的总页数,就是查询Presentation下面的Slides的长度。
如:
int
pptSum (QVarint doc)
{
auto slides = doc->querySubObject ("Slides");
auto count = slides->property ("Count");
return count.toInt ();
}
PowerPoint的页面大小
可以通过Presentation的PageSetup对象,直接查询出来页面大小SlideWidth与SlideHeight。
如:
bool
pptPageSize (QVarint doc, int *x, int *y)
{
auto setup = mDoc->querySubObject ("PageSetup");
auto width = setup->property ("SlideWidth");
auto height = setup->property ("SlideHeight");
if (x)
*x = width.toInt ();
if (y)
*y = height.toInt ();
return true;
}
导出PowerPoint成图片
PowerPoint有一点,与Word、Excel不一样,就是它可以把特定的页(即Slide),通过Slide的Export方法,导出成图片。
Slide的Export方法的原型为:
Syntax
expression.Export (FileName, FilterName, ScaleWidth, ScaleHeight)
expression A variable that represents a Slide object.
需要注意的是,FileName的路径分隔符必须是\,不能是/。
如下面的代码,把PowerPoint中特定的页数,导出到了临时文件,又加载到了QImage对象中:
bool
pptToImage (QVarint doc, int pn, QImage *pix)
{
auto slides = doc->querySubObject ("Slides");
auto slide = slides->querySubObject ("Item(int)", pn);
auto temppath
= QString ("%1/%2.png").arg (QDir::tempPath ()).arg (rand ());
temppath.replace ("/", "\\");
slide->dynamicCall ("Export(const QString &, const QString &)", temppath,
QString ("PNG"));
if (QFile::exists (temppath) == false)
{
return false;
}
*pix = QImage (temppath);
QFile::remove (temppath);
return true;
}