在RCP程序中嵌入Word文档

来源:百度文库 编辑:神马文学网 时间:2024/04/29 03:35:50
RCP技术 2007-09-27 17:17:43 阅读141 评论1 字号:大中小
在最近的项目中,有一个发送文书的功能,是使用Word作为文书模板,在发送文书之前要初使化模板中的内容,并且在文书打开之后还能编辑。eclipse提供了一系列的OLE对象操作,但是对Word文档编辑支持并不是很好,所以,在网上搜了一些关于这方面的文章,总算是完成了这个功能。
要用JAVA实现Word文档的读写,目前有几种解决方案,我用的是jacob1.12,能支持Word2003和Word2007。但是使用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,建立项目
项目的结构如图:

DsoFramer.java:这个类用来初使化DsoFramer控件并嵌入到Composite中
======================================================================
package wordsample.ole;
import org.eclipse.swt.SWT;
/**
* DsoFramer控件的初使化
* @author 严军
* @create 2007-9-27 上午11:44:34
* @version 1.0
*/
public class DsoFramer {
/**
* DsoFramer控件的初使化
* @param parent DsoFramer的容器
* @param filePath 要打开的文档
*/
public static void 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);
//Word在RCP中显示的样式
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 严军
* @create 2007-9-27 下午02:04:46
* @version 1.0
*/
public class OLESite extends OleControlSite {
public OLESite(Composite parent, int style, String progId) {
super(parent, style, progId);
addListener(SWT.Resize, new Listener() {
// addition to onResize
public void 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张表格;
* Value为ArrayList对象,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 严军
* @create 2007-9-27 下午02:05:40
* @version 1.0
*/
public class JAVAWord {
private boolean saveOnExit;
/**
* word文档
*/
private Dispatch doc = null;
/**
* word运行程序对象
*/
private ActiveXComponent word;
/**
* 所有word文档
*/
private Dispatch documents;
/**
* 构造函数
*/
public JAVAWord() {
// 初始化com的线程,非常重要!!使用结束后要调用 realease方法
ComThread.InitSTA();
saveOnExit = false;
word = new ActiveXComponent("Word.Application");
word.setProperty("Visible", new Variant(false));
documents = word.getProperty("Documents").toDispatch();
}
/**
* 设置参数:退出时是否保存
*
* @param saveOnExit
*            true-退出时保存文件,false-退出时不保存文件
*/
public void setSaveOnExit(boolean saveOnExit) {
this.saveOnExit = saveOnExit;
}
/**
* 得到参数:退出时是否保存
*
* @return boolean true-退出时保存文件,false-退出时不保存文件
*/
public boolean getSaveOnExit() {
return saveOnExit;
}
/**
* 打开文件
*
* @param inputDoc
*            要打开的文件,全路径
* @return Dispatch 打开的文件
*/
public Dispatch open(String inputDoc) {
return Dispatch.call(documents, "Open", inputDoc).toDispatch();
}
/**
* 选定内容
*
* @return Dispatch 选定的范围或插入点
*/
public Dispatch select() {
return word.getProperty("Selection").toDispatch();
}
/**
* 把选定内容或插入点向上移动
*
* @param selection
*            要移动的内容
* @param count
*            移动的距离
*/
public void moveUp(Dispatch selection, int count) {
for (int i = 0; i < count; i++)
Dispatch.call(selection, "MoveUp");
}
/**
* 把选定内容或插入点向下移动
*
* @param selection
*            要移动的内容
* @param count
*            移动的距离
*/
public void moveDown(Dispatch selection, int count) {
for (int i = 0; i < count; i++)
Dispatch.call(selection, "MoveDown");
}
/**
* 把选定内容或插入点向左移动
*
* @param selection
*            要移动的内容
* @param count
*            移动的距离
*/
public void moveLeft(Dispatch selection, int count) {
for (int i = 0; i < count; i++)
Dispatch.call(selection, "MoveLeft");
}
/**
* 把选定内容或插入点向右移动
*
* @param selection
*            要移动的内容
* @param count
*            移动的距离
*/
public void moveRight(Dispatch selection, int count) {
for (int i = 0; i < count; i++)
Dispatch.call(selection, "MoveRight");
}
/**
* 把插入点移动到文件首位置
*
* @param selection
*            插入点
*/
public void moveStart(Dispatch selection) {
Dispatch.call(selection, "HomeKey", new Variant(6));
}
/**
* 从选定内容或插入点开始查找文本
*
* @param selection
*            选定内容
* @param toFindText
*            要查找的文本
* @return boolean true-查找到并选中该文本,false-未查找到文本
*/
public boolean 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();
}
/**
* 把选定内容替换为设定文本
*
* @param selection
*            选定内容
* @param newText
*            替换为文本
*/
public void replace(Dispatch selection, String newText) {
// 设置替换文本
Dispatch.put(selection, "Text", newText);
}
/**
* 全局替换
*
* @param selection
*            选定内容或起始插入点
* @param oldText
*            要替换的文本
* @param newText
*            替换为文本
*/
public void replaceAll(Dispatch selection, String oldText, Object replaceObj) {
// 移动到文件开头
moveStart(selection);
if (oldText.startsWith("table") || replaceObj instanceof 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");
}
}
}
/**
* 替换图片
*
* @param selection
*            图片的插入点
* @param imagePath
*            图片文件(全路径)
*/
public void replaceImage(Dispatch selection, String imagePath) {
Dispatch.call(Dispatch.get(selection, "InLineShapes").toDispatch(),
"AddPicture", imagePath);
}
/**
* 替换表格
*
* @param selection
*            插入点
* @param tableName
*            表格名称,形如table$1@1、table$2@1...table$R@N,R代表从表格中的第N行开始填充,
*            N代表word文件中的第N张表
* @param fields
*            表格中要替换的字段与数据的对应表
*/
public void 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]);
}
}
}
/**
* 保存文件
*
* @param outputPath
*            输出文件(包含路径)
*/
public void save(String outputPath) {
Dispatch.call(Dispatch.call(word, "WordBasic").getDispatch(),
"FileSaveAs", outputPath);
}
/**
* 关闭文件
*
* @param document
*            要关闭的文件
*/
public void close(Dispatch doc) {
Dispatch.call(doc, "Close", new Variant(saveOnExit));
// 释放com线程。根据jacob的帮助文档,com的线程回收不由java的垃圾回收器处理
ComThread.Release();
}
/**
* 退出程序
*/
public void quit() {
word.invoke("Quit", new Variant[0]);
ComThread.Release();
}
/**
* 根据模板、数据生成word文件
*
* @param inputPath
*            模板文件(包含路径)
* @param outPath
*            输出文件(包含路径)
* @param data
*            数据包(包含要填充的字段、对应的数据)
*/
public void 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 严军
* @create 2007-9-27 下午03:31:49
* @version 1.0
*/
public class WordEditor extends EditorPart implements IConstants {
public static final String ID = "wordsample.WordEditor"; //$NON-NLS-1$
@Override
public void createPartControl(Composite parent) {
Composite container = new Composite(parent, SWT.NONE);
container.setLayout(new FillLayout());
// 初使化文档内容
JAVAWord word = new JAVAWord();
Map data = new HashMap();
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
public void setFocus() {
}
@Override
public void doSave(IProgressMonitor monitor) {
}
@Override
public void doSaveAs() {
}
@Override
public void init(IEditorSite site, IEditorInput input)
throws PartInitException {
setSite(site);
setInput(input);
}
@Override
public boolean isDirty() {
return false;
}
@Override
public boolean isSaveAsAllowed() {
return false;
}
}
以上是示例程序的主要代码,更多的内容在源代码中。
运行效果:被选中的两行是被替换掉的文字。