花了两天时间,参考了一些资料,总算是处理好了这样一个技术点。
关键的心得如下:
使用jacob,重点不是jacob本身,而是office的一些API资料。比如需要知道光标的移动, 包括上下左右的move(MoveUp, MoveDown,MoveLeft, MoveRight),包括回到首页起点Dispatch.put(selection, "Start", 0)等等。
严格的说,这边并没有很系统化的去了解jacob的底层。但对于一些关键点,还是可以拿出来分享的。比如插入一张图片之后,系统可以拿到一个Dispatch对象(例如叫做obj),我们则需要调用Dispatch.call(obj,"select"),这样相当于使用鼠标在word选中了新插入的图片,而后我们就可以通过Dispatch得到图片的ShapeRange,进而得到ShapeRange的WrapFormat,再对WrapFormat进行设定。对应的结构可以归纳为:Image->ShapeRange->WrapFormat。但是要想知道WrapFormat对应到的是哪些值,且有哪些作用,则需要去查询MSDN。这边查询到的相关值如下:
wdWrapInline 7 将形状嵌入到文字中。
wdWrapNone 3 将形状放在文字前面。请参阅 wdWrapFront 。
wdWrapSquare 0 使文字环绕形状。行在形状的另一侧延续。
wdWrapThrough 2 使文字环绕形状。
wdWrapTight 1 使文字紧密地环绕形状。
wdWrapTopBottom 4 将文字放在形状的上方和下方。
wdWrapBehind 5 将形状放在文字后面。
wdWrapFront 6 将形状放在文字前面。
这种匈牙利命名法的变量名,其实都对应到一个整型数据(应该是一个常量型的变量)。比如这次代码中需要用到的将印章图片盖在文字的前面,对应到得变量是wdWrapFront,也就是数值6.
再有就是要知道传入的word文件共有几页,加印的话,应该是每一页都要盖章的,于是就需要通过Dispatch.call(cursor,"information",4)来获取,此时cursor(光标)可能是需要回到word首页的开始位置(还未测试)。然后的思路就是要将光标指定到某个位置并以在文字前面的方式插入印章图片,实现的方式是:光标遍历到每一页的开始位置,并在此基础上移动到当前页的显眼位置。在开发过程中,将光标移动到每一页的开始位置,是花了相当的时间的。MSDN上并没有给出很直观的例子,甚至还找到了此功能无法实现的文章。直到找到了一篇名为“delphi读取WORD文档每一页的内容”的帖子,并注意到里面使用的
//定位到第i页
PageRange := wordapp.Selection.GoTo(wdGoToPage, wdGoToNext, IntToStr(i)); //<---->再一次匈牙利命名法的变量
这种不太一样的写法正是对应到了
Dispatch.invoke(this.cursor, "Goto", Dispatch.Method, new Object[] {1, 2, String.valueOf(index)}, new int[1]);//<---->匈牙利命名法的变量对应到的整型常量,参考语句出处。
以下是完整的Java代码,要正确使用的话,需要将jacob的jar包放进工程,并在运行环境中加入jacob.dll。
import com.jacob.activeX.ActiveXComponent; import com.jacob.com.Dispatch; import com.jacob.com.Variant; import com.jacob.com.ComThread; public class WordInsertPicture { public WordInsertPicture() { } // 声明一个静态的类实例化对象 private static WordInsertPicture instance; // 声明word文档对象 private Dispatch doc = null; // 声明word文档当前活动视窗对象 private Dispatch activeWindow = null; // 声明word文档选定区域或插入点对象 private Dispatch docSelection = null; // 声明所有word文档集合对象 private Dispatch wrdDocs = null; // 声明word文档名称对象 private String fileName; // 声明ActiveX组件对象:word.Application,Excel.Application,Powerpoint.Application等等 private ActiveXComponent wrdCom; /** * 获取Word操作静态实例对象 * * @return 报表汇总业务操作 */ public final static synchronized WordInsertPicture getInstance() { if (instance == null) instance = new WordInsertPicture(); return instance; } /** * 初始化Word对象 * * @return 是否初始化成功 */ public boolean initWordObj() { boolean retFlag = false; ComThread.InitSTA();// 初始化com的线程,非常重要!!使用结束后要调用 realease方法 wrdCom = new ActiveXComponent("Word.Application");// 实例化ActiveX组件对象:对word进行操作 try { /* * 返回wrdCom.Documents的Dispatch * 获取Dispatch的Documents对象,可以把每个Dispatch对象看成是对Activex控件的一个操作 * 这一步是获得该ActiveX控件的控制权。 */ wrdDocs = wrdCom.getProperty("Documents").toDispatch(); // 设置打开的word应用程序是否可见 wrdCom.setProperty("Visible", new Variant(false)); retFlag = true; } catch (Exception e) { retFlag = false; e.printStackTrace(); } return retFlag; } /** * 创建一个新的word文档 * */ public void createNewDocument() { // 创建一个新的文档 doc = Dispatch.call(wrdDocs, "Add").toDispatch(); // 获得当前word文档文本 docSelection = Dispatch.get(wrdCom, "Selection").toDispatch(); } /** * 取得活动窗体对象 * */ public void getActiveWindow() { // 获得活动窗体对象 activeWindow = wrdCom.getProperty("ActiveWindow").toDispatch(); } /** * 打开一个已存在的文档 * * @param docPath */ public void openDocument(String docPath) { if (this.doc != null) { this.closeDocument(); } this.doc = Dispatch.call(wrdDocs, "Open", docPath).toDispatch(); this.docSelection = Dispatch.get(wrdCom, "Selection").toDispatch(); } /** * 关闭当前word文档 * */ public void closeDocument() { if (this.doc != null) { Dispatch.call(this.doc, "Save"); Dispatch.call(this.doc, "Close", new Variant(true)); this.doc = null; } } /** * 文档设置图片水印 * * @param waterMarkPath * 水印路径 */ public void setWaterMark(String waterMarkPath) { // 取得活动窗格对象 Dispatch activePan = Dispatch.get(this.activeWindow, "ActivePane") .toDispatch(); // 取得视窗对象 Dispatch view = Dispatch.get(activePan, "View").toDispatch(); // 打开页眉,值为9,页脚为10 Dispatch.put(view, "SeekView", new Variant(9)); //获取页眉和页脚 Dispatch headfooter = Dispatch.get(this.docSelection, "HeaderFooter") .toDispatch(); // 获取水印图形对象 Dispatch shapes = Dispatch.get(headfooter, "Shapes").toDispatch(); // 给文档全部加上水印,设置了水印效果,内容,字体,大小,是否加粗,是否斜体,左边距,上边距。 //调用shapes对象的AddPicture方法将全路径为picname的图片插入当前文档 Dispatch picture = Dispatch.call(shapes, "AddPicture", waterMarkPath).toDispatch(); //选择当前word文档的水印 Dispatch.call(picture, "Select"); Dispatch.put(picture, "Left", new Variant(0)); Dispatch.put(picture, "Top", new Variant(150)); Dispatch.put(picture, "Width", new Variant(150)); Dispatch.put(picture, "Height", new Variant(80)); //关闭页眉 Dispatch.put(view, "SeekView", new Variant(0)); } /** * 关闭Word资源 * * */ public void closeWordObj() { // 关闭word文件 wrdCom.invoke("Quit", new Variant[] {}); // 释放com线程。根据jacob的帮助文档,com的线程回收不由java的垃圾回收器处理 ComThread.Release(); } /** * 得到文件名 * * @return . */ public String getFileName() { return fileName; } /** * 设置文件名 * * @param fileName . */ public void setFileName(String fileName) { this.fileName = fileName; } /** * 开始为word文档添加水印 * * @param wordPath * word文档的路径 * @param waterMarkPath * 添加的水印图片路径 * @return 是否成功添加 */ public boolean addWaterMark(String wordPath, String waterMarkPath) { try { if (initWordObj()) { openDocument(wordPath); getActiveWindow(); setWaterMark(waterMarkPath); closeDocument(); closeWordObj(); return true; } else return false; } catch (Exception e) { e.printStackTrace(); closeDocument(); closeWordObj(); return false; } } public boolean insertImage(String wordPath,String imagePath) { try { if (initWordObj()) { openDocument(wordPath); getActiveWindow(); // 用于指定位置MoveRight以及MoveDown Dispatch selection = Dispatch.get(wrdCom, "Selection").toDispatch(); for(int i = 0; i < 10; i++){ Dispatch.call(selection, "MoveRight"); } for(int i = 0; i < 10; i++){ Dispatch.call(selection, "MoveDown"); } Dispatch image = Dispatch.get(selection, "InlineShapes").toDispatch(); Dispatch dv = Dispatch.call(image, "AddPicture", imagePath).toDispatch(); Dispatch.call(dv, "Select"); //Dispatch Left = Dispatch.get(position, "Left").toDispatch(); selection = Dispatch.get(wrdCom, "Selection").toDispatch(); Dispatch shaperange = Dispatch.get(selection, "ShapeRange").toDispatch(); Dispatch wf = Dispatch.get(shaperange, "WrapFormat").toDispatch(); Dispatch.put(wf, "Type", "6"); int pcnt = Integer.parseInt(Dispatch.call(selection,"information",4).toString()); for(int p = 1; p < pcnt; p++){ Dispatch.invoke(selection, "Goto", Dispatch.Method, new Object[] {1, 2, String.valueOf(p)}, new int[1]); for(int i = 0; i < 10; i++){ Dispatch.call(selection, "MoveRight"); } for(int i = 0; i < 10; i++){ Dispatch.call(selection, "MoveDown"); } Dispatch imagef = Dispatch.get(selection, "InlineShapes").toDispatch(); Dispatch dvf = Dispatch.call(imagef, "AddPicture", imagePath).toDispatch(); Dispatch.call(dvf, "Select"); //Dispatch Left = Dispatch.get(position, "Left").toDispatch(); selection = Dispatch.get(wrdCom, "Selection").toDispatch(); Dispatch shaperangef = Dispatch.get(selection, "ShapeRange").toDispatch(); Dispatch wff = Dispatch.get(shaperangef, "WrapFormat").toDispatch(); Dispatch.put(wff, "Type", "6"); Dispatch.put(selection, "Start", 0); // 回到页首 } closeDocument(); closeWordObj(); return true; } else return false; } catch (Exception e) { e.printStackTrace(); closeDocument(); closeWordObj(); return false; } } /** * 测试功能 * */ public static void main(String[] argv) { WordInsertPicture wordObj = WordInsertPicture.getInstance(); //System.out.println(wordObj.getDocPages()); wordObj.insertImage("e://1//Adf.docx", "e://1//watermark.png"); //watermark.png"); } }