1.引言
许多商业应用程序允许用户在应用程序中生成基于某些数据的报表。电子表格特别适合用于生成这样的报表。电子表格不仅可以将数据经格式化以后以结构化的形式展现给用户,而且为用户提供了快速且高效的数据处理功能。正如上面所说的,OpenOffice.org的API提供了大量的类和方法以方便开发者将OpenOffice.org电子表格的功能集成到他们自己的应用程序中。在应用程序中,单击某个按钮就可以启动OpenOffice.org并将应用程序生成的数据以自定义电子表格的形式展现出来。
新手可能就这个开发领域很自然地提出一个问题:“一旦开发者正确地安装了所有需要的软件后,一个应用程序如何启动OpenOffice.org的新实例以及如何获取连接呢?”。这个问题得到了需要的回答之后,开发者还可能提出:“现在用户应用程序已经获取了OpenOffice.org的连接,那么应用程序应该如何将这些数据嵌入到电子表格中呢?”。在这篇文章中,我们将首先着重满足不熟悉OpenOffice.org的API的开发者的两个基本的需求。我们将向开发者展示如何获取到OpenOffice.org的连接,如何将应用程序的数据转化为电子表格形式的数据。接着我们将讨论一些其他的主题,这些主题包括以编程方式构建和析构电子表格、设置电子表格的单元格的背景颜色以及单元格边框的格式化。然而,这里需要注意的是我们只关注OpenOffice.org本身的集成,为了代码的可读性我们忽略了诸如错误处理之类的问题。在这篇文章的结尾,您将对OpenOffice.org的API处理电子表格和如何在您自己的应用程序中利用它们的相关知识有所了解。
这篇文章涉及的应用程序是基于Swing的应用程序,它通过使用OpenOfiice.org的API来访问OpenOffice.org的各种功能。当然,您也可以使用C++或者COM/DCOM技术来连接OpenOffice.org。此类应用程序的代码并不一定必须基于Swing来编写。这样的应用程序可以使用C++、Java servlet、Java Server Page、JavaScript、VBScript、Delphi以及Visual Basic来编写。这篇文章中使用的基于Swing的应用程序将使用NetBeans IDE来构建,并且使用NetBeans Platform作为起始点。尽管任何集成开发工具都可以被用来构建如此简单的应用程序,但是使用NetBeans进行开发具有两项优势。首先,在NetBeans中我们可以充分发挥GUI构建器(即Matisse)的功能来构建用户界面,GUI构建器可以帮助我们快速建立应用程序界面的原型。其次,将我们的应用程序基于NetBeans Platform意味着我们不需要再重头开始,而且我们可以通过其提供的模块框架来增强应用程序的可扩展性。这个应用程序将生成如下图所示的不需要任何后期处理的电子表格文档:
电子表格中的数据来自于JTable组件。在现实情况下,这些数据往往来源于数据库中。在上面述及的应用程序中,我们将把数据硬编码在程序代码中,这主要是因为数据的来源问题已经超出本篇文章的范围了。无论数据是否是来自于数据库,当用户已经完成了数据的处理后,应用程序将把JTable中的数据转换生成电子表格来呈现。除了数据之外,上面的图还展示了以下几个元素,这些元素将在下面的章节中述及:
-
表头,电子表格有一行使用特殊颜色(深蓝色)标识的表头。
-
行颜色的交错,电子表格中的其他行的颜色是交错的,有的背景色是桔色,而有的是白色。
-
高或者低的回复,最后一列展示了某篇文章相关的回复数量,回复量比较高的行的背景颜色是绿色,而回复量比较低的行的背景颜色是红色,另外,在主表格的下方的两个单元格分别使用相同的颜色来标识高或者低回复文章的作者。
-
回复的总数,“Reply”列的最后一行的下方的单元格显示了总回复数,这个单元格的格式与其他的单元格不太一样,总回复数是通过OpenOffice.org的API来使用Calc的公式计算得到的。
-
电子表格名称,在上面图形的左下角,您可以看到“Javalobby Analysis”这样的名称,而您并没有看到Calc打开时的默认的电子表(名称为“Sheet1”、“Sheet2”、“Sheet3”),如下文所阐述的,电子表的名称的更改和默认电子表的移除都可以使用编程方式来实现。
这篇文章被分为三部分,这三部分按顺序描述了开发的过程:
- 简化重复的编码任务,这一节中我们将了解OpenOffice.org的API中可复用的元素,而这些元素将在后面的章节中被集成到我们的应用程序中。
- 建立用户界面原型,为了测试最后一节中的业务逻辑,我们将构建Swing应用程序的原型。
- 集成辅助性方法,应用程序的核心是将辅助性方法和用户界面集成起来,并且执行计算,生成电子表格。
2.系统需求
在开始之前,请先确认以下的软件已经安装好了:
- OpenOffice.org,尽管这篇文章中的代码也兼容Star Office,但是因为我们使用OpenOffice.org的API相关的JAR文件,所以最好是安装OpenOffice.org。我们将使用在OpenOffice.org的安装目录下的四个JAR文件,您可以在OpenOffice.org
2.0\program\classes文件夹中找到以下四个JAR文件:juh.jar、jurt.jar、ridl.jar和unoil.jar。
- NetBeans IDE,这篇文章关注的是OpenOffice.org的API,其中讨论的代码可以使用很多种编程语言描述,可以供多种语言编写的应用程序使用。如果您想构建这篇文章中描述的基于Swing的应用程序,您就需要去下载NetBeans 5.0或者更高的版本。
注意:这篇文章中展现的应用场景并不需要使用OpenOffice.org SDK。如果我们要使用SDK中的idlc或者javamaker等工具,那么这个时候才需要SDK。
3.背景知识:简化重复的编码工作
当我们使用OpenOffice.org的API工作时,我们可能会重复地执行某些任务。比如说,我们设置电子表格表头的颜色,但是同时我们也需要设置其他各行的颜色。实际上,我们经常交替地设置各行的颜色,这样可以使得电子表格中的行更容易分辨。如果某篇文章的回复数比较高,我们会将对应的行设置为不同的颜色(绿色),而回复数比较低的行也被设置为不同的颜色(红色)。行的颜色的设置需要编写使用OpenOffice.org的API中的很多方法的几行代码,而为了避免重复编写相同的代码,我们将这些代码组织到一个辅助性方法当中去,在需要进行设置的时候,我们只需要将颜色作为参数传递就可以了。这可以使我们的代码易读性更好,更容易维护。下面我们将更详细地讨论这些辅助性方法。
请记住,以下述及的辅助性方法可以用于任何应用程序,这些辅助性方法并不依赖于本篇文章里述及的应用程序。换句话说,您可以充分地利用这些辅助性方法,在需要的时候不需要对代码进行任何修改就可以将这些代码粘贴到应用程序的Java文件中使用。您也可以在您的代码中引用这些代码,就像这篇文章中做的一样。
3.1 使用引导程序
OpenOffice.org的Java API有自己的方法来引导OpenOffice.org。所谓“引导”OpenOffice.org,我们的意思是加载OpenOffice.org的启动程序。这通过寻找juh.jar文件所在的位置,然后在这个位置或者上一级目录查找soffice(.exe)来实现。这需要将juh.jar文件置于系统变量CLASSPATH所描述的目录中,这样本章构建的应用程序就可以访问到这个文件。然而,这里需要将juh.jar文件随同应用程序一起分发,这种情况下,这种引导机制就不奏效了。
为了解决这个问题,有两种可能的方法。首先,可以确保Java随时都可以查找到soffice(.exe),这可以通过将包含可执行文件的目录加入到Windows的PATH系统变量中(在Mac、Unix和Linux中就是LD_LIBRARY_PATH系统变量)。这种方法需要用户进行一些操作,而我们并不希望这样做。
因此,我们更倾向于推荐第二种方法,这种方法需要与访问修饰符协同工作。在Sun的JDK中,ClassLoader系统类是URLClassLoader类的实例。这个类有一个私有方法addURL,这个方法在Java系统开始的时候将被调用,从而将JAR文件以及其他相关资源添加到系统环境中。通过反射机制,我们获取一个URLClassLoader的实例,尔后使得addURL方法达到可访问状态,然后再将包含可执行文件的目录添加到URLClassLoader的URL栈中。这虽然显得很晦涩,但是这种方法很奏效。
但是,它真的那么奏效吗?与系统类的访问修饰周旋总是一件冒险的事情。addURL方法被声明为protected型的,自然有其理由。另外,谁能保证使用的一定是Sun的JDK呢?或者Sun可能在随后的版本中忽略这个方法?然而,Java规范对上述这些事情并没有作出明确的声明,因此别的JDK在默认情况下并不是将ClassLoader类的类型配置为URLClassLoader。正是这个原因,我们使用“loader instanceof URLClassLoader”这样的检查代码来确保事情是如预期那样的。这也是我们在用户没有使用Sun的JDK的情况下确保应用程序没有任何异常情况而需付出的代价。
关于过程中构建对象的更详细的信息请参考OpenOffice.org的开发指南《第6章 Office开发》。
public Object simpleBootstrap(String pathToExecutable) throws Exception
{
//Get the executable from the incoming String:
String ooBaseDirectory = pathToExecutable.replaceAll("soffice(.exe){0,1}$","");
System.out.println("Your ooBaseDir is: " + ooBaseDirectory);
ClassLoader loader = ClassLoader.getSystemClassLoader();
if (loader instanceof URLClassLoader){
URLClassLoader cl = (URLClassLoader)loader;
Class sysclass = URLClassLoader.class;
try {
Method method = sysclass.getDeclaredMethod
("addURL", new Class[]{URL.class});
method.setAccessible(true);
method.invoke(cl, new Object[]{new File(ooBaseDirectory).toURL()});
} catch (Throwable t) {
t.printStackTrace();
throw new IOException("Error, could not add URL to system classloader");
}
} else {
System.out.println("Error occured, URLClassLoader expected but " +
loader.getClass() + " received. Could not continue.");
}
//Get the office component context:
XComponentContext xContext = Bootstrap.bootstrap();
//Get the office service manager:
XMultiComponentFactory xServiceManager = xContext.getServiceManager();
//Create the desktop, which is the root frame of the
//hierarchy of frames that contain viewable components:
Object desktop = xServiceManager.createInstanceWithContext
("com.sun.star.frame.Desktop", xContext );
return desktop;
}
另一中方法就是使用远程连接。在远程连接中,服务器名称和端口号作为参数传递给远程连接方法,然后这个方法启动OpenOffice.org并返回Desktop对象,这个对象是利用OpenOffice.org工作的起点。而且在远程连接的情况下,您可以让用户选择服务器和端口,或者您可以在代码中使用系统设置来提供服务器和端口,这都看您的选择。
本文译自NetBeans.org中的文章,其中的代码也都经过译者测试。未完待续!!!