将excel嵌入到swt的FormPage之后,有一个很重要的问题需要解决,开发人员在进行页面设计时,需要通过有效的辅助手段实现对开发的支持,比如将某个单元格与数据字段进行绑定,这就需要实现对开发人员操作的监听,即捕获操作人员选中单元格的事件,通过属性视图设置属性;这涉及到两个问题:
1、选中单元格时通知属性视图
2、通过属性视图设置属性值以后通知EXCEL的单元格
这一节我们仅讨论如何在选中单元格以后通知属性视图。
与ACTIVEX控件交互从来就不是一件容易的事,特别的是在JAVA开发环境下,但原理是完全一样的,要完成与ACTIVEX控件的交互我们先看一下ACTIVEX控件的原理以及所公布的接口及交互方式。
ActiveX控件定义
ActiveX 是一个开放的集成平台,为开发人员、 用户和 Web生产商提供了一个快速而简便的在 Internet 和
Intranet
创建程序集成和内容的方法,ActiveX插件以前也叫做OLE控件或OCX控件,它是一些软件组件或对象,可以将其插入到WEB网页或其它应用程序中
从体系角度讲,ActiveX控件是建立在COM基础之上的,COM是一个组件模型,COM组件可实现不同应用程序之间的沟通和交互,通过有效的接口向外提供服务,在SOA出现之前,COM、EJB、CORBA是三大组件模型,COM更多的是作为一个技术标准而存在,而ActiveX基于COM,提供了更进一步的网络应用与用户交互为主。
ActiveX交互
ActiveX控件所有可被外部访问的接口都公布为dispInterface的形式,是一种纯粹的自动化接口,只能通过自动化的方式来进行调用,我们在对ActiveX控件所提供的接口进行调用以及属性进行访问时,需要知道它所提供的dispid,这个id在ActiveX控件中是唯一的
在java中,OleAutomation代表了ActiveX中可访问的不同对象,在excel中体现在workbook、sheet、cell等,通过getProperty与setProperty实现对属性的访问和方法的调用,也可以通过invoke方法实现对OleAutomation提供的方法进行调用,在进行调用之前需要知道对应的dispid,dispid可以通过以下几种方式得到,微软提供的oleview.exe或通过delphi加载ActiveX控件,生成_tld.pas文件,参考下面delphi生成的pas文件:
property
Formula: OleVariant dispid 261;
property
FormulaArray: OleVariant dispid 586;
property
FormulaLabel: XlFormulaLabel dispid 1380;
property
FormulaHidden: OleVariant dispid 262;
property
FormulaLocal: OleVariant dispid 263;
property
FormulaR1C1: OleVariant dispid 264;
property
FormulaR1C1Local: OleVariant dispid 265;
function
FunctionWizard: OleVariant; dispid 571;
function
GoalSeek(Goal: OleVariant; const ChangingCell: ExcelRange):
WordBool; dispid 472;
function
Group(Start: OleVariant; End_: OleVariant; By: OleVariant; Periods:
OleVariant): OleVariant; dispid 46;
property
HasArray: OleVariant readonly dispid 266;
property
HasFormula: OleVariant readonly dispid 267;
property
Height: OleVariant readonly dispid 123;
上面的代码中不同的dispid表示了不同的属性或方法。
swt提供了对ActiveX控件事件监听的能力,还是通过代码来讲解吧,有一点复杂,呵呵
//定义应用事件GUID,这也是从pas文件中找到的,我们需要指定对应用事件进行监听
public
final static GUID IID_AppEvents =
COMObject.IIDFromString("{00024413-0000-0000-C000-000000000046}");
//1558是SheetSelectionChange事件的dispid
public
final static int SheetSelectionChange = 1558;
//将excel的container即OleControlSite与activex绑定起来,实现事件消息的捕获
public
void addEventListener(OleControlSite site, int eventID, OleListener
listener) {
IDispatch
excelApp = getApplication(site);
if
(excelApp != null) {
site.addEventListener(excelApp.getAddress(),
IID_AppEvents, eventID, listener);
}
}
//取得excel
application对象
private
IDispatch getApplication(OleControlSite site) {
IDispatch
application = null;
String
progID = site.getProgramID();
if
(progID.startsWith("Excel.Sheet.")) {
OleAutomation
excelSheet = new OleAutomation(site);
int[]
dispIDs = excelSheet.getIDsOfNames(new String[] { "Application"
});
Variant
pVarResult = excelSheet.getProperty(dispIDs[0]);
if
(pVarResult != null &&
pVarResult.getType() != COM.VT_EMPTY) {
application
= pVarResult.getDispatch();
excelapplication
= pVarResult.getAutomation();
}
excelSheet.dispose();
excelSheet
= null;
}
else
{ // I don't care.
}
return
application;
}
准备完成了,实现监听吧
void innerExcel() {
final OleControlSite clientSite = new OleControlSite(frame,
SWT.None, "Excel.Sheet");
this.addEventListener(clientSite, SheetSelectionChange, new
OleListener() {
public void handleEvent(OleEvent event) {
OleControlSite oleControlSite = (OleControlSite)
event.widget;
// 获得Excel的workbook对象
OleAutomation workbook = new OleAutomation(oleControlSite);
//
获得workbook的第一个Sheet页
OleAutomation
sheet = workbook.getProperty(DispIDS.SHEET_ID, new Variant[] {
new Variant(1) }).getAutomation();
//取得当前选择区域,DispIDS.activeCell=305
OleAutomation activityCell = excelapplication.getProperty
(DispIDS.activeCell).getAutomation();
//取得当前选中区域的行,DispIDS.cellRow=257
int selectRow = Integer.parseInt(activityCell.getProperty
(DispIDS.cellRow).getString());
//取得当前选中区域的行,DispIDS.cellRow=240
int selectColumn = Integer.parseInt(activityCell.getProperty
(DispIDS.cellColumn).getString());
System.out.println("您选中的单元格行号为:"+selectRow);
System.out.println("您选中的单元格列号为:"+selectColumn );
}