在RCP程序中嵌入Word文档

来源:互联网 发布:three.js下载 编辑:程序博客网 时间:2024/04/29 04:15

在最近的项目中,有一个发送文书的功能,是使用Word作为文书模板,在发送文书之前要初使化模板中的内容,并且在文书打开之后还能编辑。eclipse提供了一系列的OLE对象操作,但是对Word文档编辑支持并不是很好,所以,在网上搜了一些关于这方面的文章,总算是完成了这个功能。

要用JAVA实现Word文档的读写,目前有几种解决方案,我用的是jacob1.12,能支持Word2003Word2007。但是使用jacob也有个缺点,他不能嵌入RCP中运行,所以,只能先把要预设的Word内容用jacob写入文档中并保存。要把Word文档显示在RCP程序中,还要借助另外一个ActiveX控件:DsoFramer,这也是一个用得比较多的控件,我用的是DsoFramer1.2.1223.0。多的不说,下面把主要的过程列出来。

 

1,环境配置:

Eclipse3.2.2                    不用说了

Jacob1.1.2                       jacob.dll复制到C:\WINDOWS下即可

DsoFramer1.2.1223.0      运行RegSvr32.exe dsoframer.ocx来注册ocx控件

Word示例文件:                Word-RCP示例.doc复制到本地磁盘中,默认是d:\\

 

2,建立项目

项目的结构如图:

 

 在RCP程序中嵌入Word文档 - 严军 - Jonny的博客

 

DsoFramer.java:这个类用来初使化DsoFramer控件并嵌入到Composite

======================================================================

package wordsample.ole;

 

import org.eclipse.swt.SWT;

 

/**

 *DsoFramer控件的初使化

 *@author严军

 *@create2007-9-27上午11:44:34

 *@version1.0

 */

publicclass DsoFramer {

    /**

     *DsoFramer控件的初使化

     *@paramparentDsoFramer的容器

     *@paramfilePath要打开的文档

     */

    publicstaticvoid initDsoFramer(Composite parent, String filePath) {

        //初使化DsoFramer控件

       OleFrame oleFrame = new OleFrame(parent, SWT.NONE);

       OLESite site = new OLESite(oleFrame, SWT.NONE,"DSOFramer.FramerControl");

       site.doVerb(OLE.OLEIVERB_INPLACEACTIVATE);

       //WordRCP中显示的样式

       OleAutomation automation =new OleAutomation(site);

       //显示标题栏

       int ids[] = automation.getIDsOfNames(new String[] { "Titlebar" });

       automation.setProperty(ids[0],new Variant[] {new Variant(false) });

       //显示菜单栏

       ids = automation.getIDsOfNames(new String[] {"Menubar" });

       automation.setProperty(ids[0],new Variant[] {new Variant(false) });

       //显示工具栏

       ids = automation.getIDsOfNames(new String[] {"Toolbars" });

       automation.setProperty(ids[0],new Variant[] {new Variant(true) });

       //边框样式

       ids = automation.getIDsOfNames(new String[] {"BorderStyle" });

       automation.setProperty(ids[0],new Variant[] {new Variant(1) });

       //打开文档

       ids = automation.getIDsOfNames(new String[] {"Open" });

       automation.invoke(ids[0],new Variant[] {new Variant(filePath) });

    }

}

 

 

 

 

 

OLESite.java:这是对OleControlSite作了个封装,主要是布局

======================================================================

 

package wordsample.ole;

 

import org.eclipse.swt.SWT;

 

/**

 *OleControlSite进行布局的类

 *@author严军

 *@create2007-9-27下午02:04:46

 *@version1.0

 */

publicclass OLESiteextends OleControlSite {

    public OLESite(Composite parent,int style, String progId) {

       super(parent, style, progId);

       addListener(SWT.Resize,new Listener() {

           // addition to onResize

           publicvoid handleEvent(Event event) {

              if (objIOleObject !=null) {

                  Rectangle area =frame.getClientArea();

                  SIZE size = new SIZE();

                  size.cx = area.width;

                  size.cy = area.height;

                  size = xFormPixelsToHimetric(size);

                  objIOleObject.SetExtent(COM.DVASPECT_CONTENT, size);

              }

           }

       });

    }

 

    // copied from OleClientSite

    private SIZE xFormPixelsToHimetric(SIZE aSize) {

       int hDC = OS.GetDC(0);

       int xppi = OS.GetDeviceCaps(hDC, 88);// logical pixels/inch in x

       int yppi = OS.GetDeviceCaps(hDC, 90);// logical pixels/inch in y

       OS.ReleaseDC(0, hDC);

       int cx = Compatibility.round(aSize.cx * 2540, xppi); // 2540

                                                       // HIMETRIC

                                                       // units per

                                                       // inch

       int cy = Compatibility.round(aSize.cy * 2540, yppi);

       SIZE size = new SIZE();

       size.cx = cx;

       size.cy = cy;

       return size;

    }

}

 

 

JAVAWord.java:这是一个提供了jacob常用操作的类,在网上看到的,因为作者整理得非常好,所有就借了过来,作者的BLOG:http://www.javaflag.com/blog/

在这里面主要的方法是查找模板文档中的特定字符并对这些字符进行替换,当然也有其他的方法,如使用超链接。

======================================================================

 

package wordsample.ole;

 

/*************************************

 *

 *作用:利用jacob插件根据模板word生成word文件!

 *

 *传入数据为HashMap对象,对象中的Key代表word模板中要替换的字段,Value代表用来替换的值。

 *word模板中所有要替换的字段(即HashMap中的Key)以特殊字符开头和结尾,如:$code$$date$……,以免执行错误的替换。

 *所有要替换为图片的字段,Key中需包含image或者Value为图片的全路径(目前只判断文件后缀名为:.bmp.jpg.gif)。

 *要替换表格中的数据时,HashMap中的Key格式为“table$R@N”,其中:R代表从表格的第R行开始替换,N代表word模板中的第N张表格;

 *ValueArrayList对象,ArrayList中包含的对象统一为String[],一条String[]代表一行数据,ArrayList中第一条记录为特殊记录,

 *记录的是表格中要替换的列号,如:要替换第一列、第三列、第五列的数据,则第一条记录为String[3]{“1”,”3”,”5”}

 *

 ************************************/

 

import java.util.Iterator;

import java.util.List;

import java.util.Map;

 

import com.jacob.activeX.ActiveXComponent;

import com.jacob.com.ComThread;

import com.jacob.com.Dispatch;

import com.jacob.com.Variant;

 

/**

 *@author严军

 *@create2007-9-27下午02:05:40

 *@version1.0

 */

publicclass JAVAWord {

    privatebooleansaveOnExit;

 

    /**

     *word文档

     */

    private Dispatchdoc = null;

 

    /**

     *word运行程序对象

     */

    private ActiveXComponentword;

 

    /**

     *所有word文档

     */

    private Dispatchdocuments;

 

    /**

     *构造函数

     */

    public JAVAWord() {

       //初始化com的线程,非常重要!!使用结束后要调用 realease方法

       ComThread.InitSTA();

       saveOnExit =false;

       word =new ActiveXComponent("Word.Application");

       word.setProperty("Visible",new Variant(false));

       documents =word.getProperty("Documents").toDispatch();

    }

 

    /**

     *设置参数:退出时是否保存

     *

     *@paramsaveOnExit

     *           true-退出时保存文件,false-退出时不保存文件

     */

    publicvoid setSaveOnExit(boolean saveOnExit) {

       this.saveOnExit = saveOnExit;

    }

 

    /**

     *得到参数:退出时是否保存

     *

     *@returnbooleantrue-退出时保存文件,false-退出时不保存文件

     */

    publicboolean getSaveOnExit() {

       returnsaveOnExit;

    }

 

    /**

     *打开文件

     *

     *@paraminputDoc

     *           要打开的文件,全路径

     *@returnDispatch打开的文件

     */

    public Dispatch open(String inputDoc) {

       return Dispatch.call(documents,"Open", inputDoc).toDispatch();

    }

 

    /**

     *选定内容

     *

     *@returnDispatch选定的范围或插入点

     */

    public Dispatch select() {

       returnword.getProperty("Selection").toDispatch();

    }

 

    /**

     *把选定内容或插入点向上移动

     *

     *@paramselection

     *           要移动的内容

     *@paramcount

     *           移动的距离

     */

    publicvoid moveUp(Dispatch selection,int count) {

       for (int i = 0; i < count; i++)

           Dispatch.call(selection,"MoveUp");

    }

 

    /**

     *把选定内容或插入点向下移动

     *

     *@paramselection

     *           要移动的内容

     *@paramcount

     *           移动的距离

     */

    publicvoid moveDown(Dispatch selection,int count) {

       for (int i = 0; i < count; i++)

           Dispatch.call(selection,"MoveDown");

    }

 

    /**

     *把选定内容或插入点向左移动

     *

     *@paramselection

     *           要移动的内容

     *@paramcount

     *           移动的距离

     */

    publicvoid moveLeft(Dispatch selection,int count) {

       for (int i = 0; i < count; i++)

           Dispatch.call(selection,"MoveLeft");

    }

 

    /**

     *把选定内容或插入点向右移动

     *

     *@paramselection

     *           要移动的内容

     *@paramcount

     *           移动的距离

     */

    publicvoid moveRight(Dispatch selection,int count) {

       for (int i = 0; i < count; i++)

           Dispatch.call(selection,"MoveRight");

    }

 

    /**

     *把插入点移动到文件首位置

     *

     *@paramselection

     *           插入点

     */

    publicvoid moveStart(Dispatch selection) {

       Dispatch.call(selection,"HomeKey", new Variant(6));

    }

 

    /**

     *从选定内容或插入点开始查找文本

     *

     *@paramselection

     *           选定内容

     *@paramtoFindText

     *           要查找的文本

     *@returnbooleantrue-查找到并选中该文本,false-未查找到文本

     */

    publicboolean find(Dispatch selection, String toFindText) {

       //selection所在位置开始查询

       Dispatch find = Dispatch.call(selection,"Find").toDispatch();

       //设置要查找的内容

       Dispatch.put(find,"Text", toFindText);

       //向前查找

       Dispatch.put(find,"Forward", "True");

       //设置格式

       Dispatch.put(find,"Format", "True");

       //大小写匹配

       Dispatch.put(find,"MatchCase", "True");

       //全字匹配

       Dispatch.put(find,"MatchWholeWord", "True");

       //查找并选中

       return Dispatch.call(find,"Execute").getBoolean();

    }

 

    /**

     *把选定内容替换为设定文本

     *

     *@paramselection

     *           选定内容

     *@paramnewText

     *           替换为文本

     */

    publicvoid replace(Dispatch selection, String newText) {

       //设置替换文本

       Dispatch.put(selection,"Text", newText);

    }

 

    /**

     *全局替换

     *

     *@paramselection

     *           选定内容或起始插入点

     *@paramoldText

     *           要替换的文本

     *@paramnewText

     *           替换为文本

     */

    publicvoid replaceAll(Dispatch selection, String oldText, Object replaceObj) {

       //移动到文件开头

       moveStart(selection);

       if (oldText.startsWith("table") || replaceObjinstanceof List) {

           replaceTable(selection, oldText, (List) replaceObj);

       } else {

           String newText = (String) replaceObj;

           if (oldText.indexOf("image") != -1

                  || newText.lastIndexOf(".bmp") != -1

                  || newText.lastIndexOf(".jpg") != -1

                  || newText.lastIndexOf(".gif") != -1)

              while (find(selection, oldText)) {

                  replaceImage(selection, newText);

                  Dispatch.call(selection,"MoveRight");

              }

           else

              while (find(selection, oldText)) {

                  replace(selection, newText);

                  Dispatch.call(selection,"MoveRight");

              }

       }

    }

 

    /**

     *替换图片

     *

     *@paramselection

     *           图片的插入点

     *@paramimagePath

     *           图片文件(全路径)

     */

    publicvoid replaceImage(Dispatch selection, String imagePath) {

       Dispatch.call(Dispatch.get(selection,"InLineShapes").toDispatch(),

              "AddPicture", imagePath);

    }

 

    /**

     *替换表格

     *

     *@paramselection

     *           插入点

     *@paramtableName

     *           表格名称,形如table$1@1table$2@1...table$R@NR代表从表格中的第N行开始填充,

     *           N代表word文件中的第N张表

     *@paramfields

     *           表格中要替换的字段与数据的对应表

     */

    publicvoid replaceTable(Dispatch selection, String tableName, List dataList) {

       if (dataList.size() <= 1) {

           System.out.println("Empty table!");

           return;

       }

       //要填充的列

       String[] cols = (String[]) dataList.get(0);

       //表格序号

       String tbIndex = tableName.substring(tableName.lastIndexOf("@") + 1);

       //从第几行开始填充

       int fromRow = Integer.parseInt(tableName.substring(tableName

              .lastIndexOf("$") + 1, tableName.lastIndexOf("@")));

       //所有表格

       Dispatch tables = Dispatch.get(doc,"Tables").toDispatch();

       //要填充的表格

       Dispatch table = Dispatch.call(tables,"Item", new Variant(tbIndex))

              .toDispatch();

       //表格的所有行

       Dispatch rows = Dispatch.get(table,"Rows").toDispatch();

       //填充表格

       for (int i = 1; i < dataList.size(); i++) {

           //某一行数据

           String[] datas = (String[]) dataList.get(i);

           //在表格中添加一行

           if (Dispatch.get(rows,"Count").getInt() < fromRow + i - 1)

              Dispatch.call(rows,"Add");

           //填充该行的相关列

           for (int j = 0; j < datas.length; j++) {

              //得到单元格

              Dispatch cell = Dispatch.call(table,"Cell",

                     Integer.toString(fromRow + i - 1), cols[j])

                     .toDispatch();

              //选中单元格

              Dispatch.call(cell,"Select");

              //设置格式

              Dispatch font = Dispatch.get(selection,"Font").toDispatch();

              Dispatch.put(font,"Bold", "0");

              Dispatch.put(font,"Italic", "0");

              //输入数据

              Dispatch.put(selection,"Text", datas[j]);

           }

       }

    }

    /**

     *保存文件

     *

     *@paramoutputPath

     *           输出文件(包含路径)

     */

    publicvoid save(String outputPath) {

       Dispatch.call(Dispatch.call(word,"WordBasic").getDispatch(),

              "FileSaveAs", outputPath);

    }

 

    /**

     *关闭文件

     *

     *@paramdocument

     *           要关闭的文件

     */

    publicvoid close(Dispatch doc) {

       Dispatch.call(doc,"Close", new Variant(saveOnExit));

       //释放com线程。根据jacob的帮助文档,com的线程回收不由java的垃圾回收器处理

       ComThread.Release();

    }

 

    /**

     *退出程序

     */

    publicvoid quit() {

       word.invoke("Quit",new Variant[0]);

       ComThread.Release();

    }

 

    /**

     *根据模板、数据生成word文件

     *

     *@paraminputPath

     *           模板文件(包含路径)

     *@paramoutPath

     *           输出文件(包含路径)

     *@paramdata

     *           数据包(包含要填充的字段、对应的数据)

     */

    publicvoid toWord(String inputPath, String outPath, Map data) {

       String oldText;

       Object newValue;

       try {

           doc = open(inputPath);

           Dispatch selection = select();

           Iterator keys = data.keySet().iterator();

           while (keys.hasNext()) {

              oldText = (String) keys.next();

              newValue = data.get(oldText);

              replaceAll(selection, oldText, newValue);

           }

           save(outPath);

       } catch (Exception e) {

           // debug.println("toword[Java2Word]------------操作word文件失败!"+e.getMessage(),true);

 

       } finally {

           if (doc !=null)

              close(doc);

       }

    }

 

 

WordEditor.java:编辑器,作为Word编辑的容器

======================================================================

 

package wordsample.ui;

 

import java.util.HashMap;

 

/**

 *编辑器,打开Word文档

 *@author严军

 *@create2007-9-27下午03:31:49

 *@version1.0

 */

publicclass WordEditorextends EditorPartimplements IConstants {

 

    publicstaticfinal StringID ="wordsample.WordEditor";//$NON-NLS-1$

 

    @Override

    publicvoid createPartControl(Composite parent) {

       Composite container = new Composite(parent, SWT.NONE);

       container.setLayout(new FillLayout());

      

       //初使化文档内容

       JAVAWord word = new JAVAWord();

       Map<String, String> data =new HashMap<String, String>();

      

       data.put("$projectName$","RCP-Word示例");

       data.put("$author$","严军");

      

       try {

           word.toWord(FILE_PATH,FILE_PATH, data);

       } catch (Exception e) {

           e.printStackTrace();

       }

      

       //初使化DsoFramer

       DsoFramer.initDsoFramer(container,FILE_PATH);

    }

 

    @Override

    publicvoid setFocus() {

    }

 

    @Override

    publicvoid doSave(IProgressMonitor monitor) {

    }

 

    @Override

    publicvoid doSaveAs() {

    }

 

    @Override

    publicvoid init(IEditorSite site, IEditorInput input)

           throws PartInitException {

       setSite(site);

       setInput(input);

    }

 

    @Override

    publicboolean isDirty() {

       returnfalse;

    }

 

    @Override

    publicboolean isSaveAsAllowed() {

       returnfalse;

    }

 

}

 

以上是示例程序的主要代码,更多的内容在源代码中。

运行效果:被选中的两行是被替换掉的文字。

 

 

 在RCP程序中嵌入Word文档 - 严军 - Jonny的博客

原创粉丝点击