JFace简介

JFace是在SWT之上的一层抽象。在SWT中,你通常创建控件,给它们添加数据,调用它们的方法。JFace从基本的直接与控件打交道上退了一步,将他们包装成一个层次,以使这些控件使用起来更加简单。它隐藏了许多实现的细节,减少了为了实现目标而必须写的代码行数。
  和SWT不一样,JFace并没有现成的和Eclipse分开发布。这意味着你必须安装Eclipse以获得JFace。JFace并不要求你在硬盘上保留Eclipse,所以如果愿意的话,你可以自由的将JFace的JAR文件复制到其他目录下,然后将Eclipse删去。JFace的JAR文件全部在eclipse/plugins目录下,分散在不同的JAR文件中:

org.eclipse.jface_3.0.0中的jface.jar
org.eclipse.core.runtime_3.0.0中的runtime.jar
org.eclipse.osgi_3.0.0中的osgi.jar
org.eclipse.jface.text_3.0.0中的jfacetext.jar
org.eclipse.text_3.0.0中的text.jar
  你可以将这些文件复制到你喜欢的任何地方,并且必须将这些文件(或者至少是你用到的那些)与你的JFace程序一起发布。你并不需要在每一个程序中都用到所有这些文件,所以可以仅仅发布你的程序所依赖的那部分。



问候JFace的世界

  HelloWorld程序又一次向世界问候了,不过这一次是用JFace。因为JFace添加了一些Java库(但是并没有本地库——记住它是建立在SWT之上的),你需要一个新的Ant文件(见清单13-1)去生成和运行这个程序。

清单13-1: build.xml

<project name="GenericJFaceApplication" default="run" basedir=".">
<description>
    Generic JFace Application build and execution file
</description>

<property name="main.class" value=""/>
<property name="src"         location="."/>
<property name="build"       location="."/>

<!-根据你的Eclipse主目录更新location的值 -->
<property name="ecl.home" location="c:\eclipse"/>

<!-根据你的窗口系统(win32、gtk、motif等等)更新value的值 -->
<property name="win.sys"   value="win32"/>

<!-根据你的操作系统(win32、linux等等)更新value的值 -->
<property name="os.sys"    value="win32"/>

<!-根据你机器的体系结构更新value的值 -->
<property name="arch"      value="x86"/>

<!-根据你的SWT版本更新value的值 -->
<property name="swt.ver"   value="3.0.0"/>

<!-不要修改这行以下的代码 -->
<property name="swt.subdir"
location="${ecl.home}/plugins/org.eclipse.swt.${win.sys}_${swt.ver}"/>
<property name="swt.jar.lib" location="${swt.subdir}/ws/${win.sys}"/>
<property name="swt.jni.lib"
    location="${swt.subdir}/os/${os.sys}/${arch}"/>
<property name="runtime.jar.lib"
    location="${ecl.home}/plugins/org.eclipse.core.runtime_${swt.ver}"/>
<property name="jface.jar.lib"
    location="${ecl.home}/plugins/org.eclipse.jface_${swt.ver}"/>
<property name="osgi.jar.lib"
    location="${ecl.home}/plugins/org.eclipse.osgi_${swt.ver}"/>
<property name="jfacetext.jar.lib"
    location="${ecl.home}/plugins/org.eclipse.jface.text_${swt.ver}"/>
<property name="text.jar.lib"
    location="${ecl.home}/plugins/org.eclipse.text_${swt.ver}"/>

<path id="project.class.path">
<pathelement path="${build}"/>
    <fileset dir="${swt.jar.lib}">
      <include name="**/*.jar"/>
    </fileset>
    <fileset dir="${runtime.jar.lib}">
      <include name="**/*.jar"/>
    </fileset>
    <fileset dir="${jface.jar.lib}">
      <include name="**/*.jar"/>
    </fileset>
    <fileset dir="${osgi.jar.lib}">
      <include name="**/*.jar"/>
    </fileset>
    <fileset dir="${jfacetext.jar.lib}">
      <include name="**/*.jar"/>
    </fileset>
    <fileset dir="${text.jar.lib}">
      <include name="**/*.jar"/>
    </fileset>
</path>

<target name="compile">
    <javac srcdir="${src}" destdir="${build}">
      <classpath refid="project.class.path"/>
    </javac>
</target>

<target name="run" depends="compile">
    <java classname="${main.class}" fork="true" failonerror="true">
      <jvmarg value="-Djava.library.path=${swt.jni.lib}"/>
      <classpath refid="project.class.path"/>
    </java>
</target>
</project>


  正如你所见,这个build.xml文件向classpath中添加了一些JFace的JAR文件。确保根据这个文件里的注释,按照你的操作系统、窗口系统等更新你的这个文件。如果你使用的是Eclipse,你可以添加这些JAR文件到项目属性页的Java Build Path这一部分。

  清单13-2包含了HelloWorld的源代码。

清单13-2: HelloWorld.java

package examples.ch13;

import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;

/**
* 你的第一个JFace应用程序
*/
public class HelloWorld extends ApplicationWindow {
  /**
   * HelloWorld的构造函数
   */
  public HelloWorld() {
    super(null);
  }

  /**
   * 运行程序
   */
  public void run() {
    // 让open()方法在窗口被关闭之前都不返回
    setBlockOnOpen(true);

    // 打开主窗口
    open();

    // 将display销毁
    Display.getCurrent().dispose();
  }

  /**
   * 创建主窗口的内容
   *
   * @param parent 主窗口
   * @return Control
   */
  protected Control createContents(Composite parent) {
    // Create a Hello, World label
    Label label = new Label(parent, SWT.CENTER);
    label.setText("Hello, World");
    return label;
  }

  /**
   * 程序的入口点
   *
   * @param args 命令行参数
   */
  public static void main(String[] args) {
new HelloWorld().run();
  }
}


  像你对SWT程序所做的那样编译并运行HelloWorld:

ant -Dmain.class=examples.ch13.HelloWorld


  在提示符下发出这个命令就可以看到如图13-1所示的窗口。



图13-1: JFace的HelloWorld
  首先注意到的是HelloWorld类继承自一个ApplicationWindow类,这个类是JFace对Shell的抽象。当你在代码编辑器中敲入extends这个词的时候,SWT会让你觉得心虚,因为如此之多的SWT类(包括Shell)带有警告说它们并不是设计用来被继承的。别担心,继承一个ApplicationWindow类不仅是合法的,而且是提倡的用法。

  接着,你找不到典型的SWT事件循环了:

Display display = new Display();
Shell shell = new Shell();
// 创建shell的内容
shell.open();
while (!shell.isDisposed()) {
  if (!display.readAndDispatch()) {
    display.sleep();
  }
}
display.dispose();


  取而代之的是一段更加简洁的代码:

setBlockOnOpen(true);
open();
Display.getCurrent().dispose();


  第一个方法调用,setBlockOnOpen(),设置了这样一个标记:当它为真的时候,告诉下一个方法,open(),进入一个和原先SWT事件循环非常类似的事件循环。将true传给setBlockOnOpen()导致open()在窗口关闭之前不返回。然而当我们注意到第三个方法调用Display.getCurrent().dispose()的时候,JFace的优雅带来的愉悦稍许的淡了一些:你仍然需要销毁你所创建的。这是为了使用JFace带来的简单性而付出的一个小小的代价。

  这个HelloWorld程序也没有显式的指定布局,因为默认的使用了一个叫做ApplicationWindowLayout的内部类来满足你所有的需求。它也不会显式的调用createContents()方法,而是依靠JFace框架去做。这里的代码比这本书里那些SWT的例子更加整洁,暴露更少的细节。



理解SWT和JFace的关系

  不要觉得前面学习SWT是在浪费时间,觉得一旦拥有JFace之后就再也不用见到SWT了,事实上SWT决不仅仅总是简单的被JFace调用[1]。不但抽象会有漏洞,而且JFace也没有覆盖SWT的全部。尽管你沉浸在JFace当中,你仍然可以从SWT的知识中得到许多好处。

  因为JFace使用了SWT,并且因为JFace是构建在SWT之上的,所以它需要SWT的JAR文件和本地库文件。也就是说,JFace应用程序需要SWT应用程序所需要的所有东西,再加上JFace的JAR文件。

  在JFace程序中直接调用SWT,可能会让你的程序锦上添花,也可能会让你的程序挂掉。在有效并且合适的时候使用JFace的抽象,并且把SWT作为实现程序要求的退一步的依靠。



理解ApplicationWindow类

  本章中的HelloWorld程序继承了ApplicationWindow类。ApplicationWindow正如它的名字一样,表示了一个窗口应用程序。它有一个父亲Shell,是从构造函数传进去的:

ApplicationWindow(Shell parentShell)

  如果parentShell是null,这个ApplicationWindow就代表一个顶层窗口,否则它就是parentShell的一个孩子。它包含了对菜单栏、工具条、CoolBar以及状态栏的支持。

  当你构造一个ApplicationWindow的时候,除了构造它本身以外没有什么事情会发生。当你调用它的open()方法的时候,会开始很多工作,并且最有趣的事情发生在当父亲Shell为null的时候。在这种情况下,父亲Shell被创建,然后configureShell()被调用。ApplicationWindow中的configureShell实现依次做以下事情:

设置默认图像
设置一个GridLayout
如果菜单栏被设置了,就创建一个菜单
将布局变为ApplicationWindowLayout
如果工具栏被设置了,就创建一个工具栏
如果CoolBar被设置了,就创建一个CoolBar
如果状态栏被设置了,就创建一个状态栏
你可以重载configureShell()以改变默认的行为。
  接下来,这个ApplicationWindow会被按需要改变尺寸,以使得它不会超出屏幕大小。接着它被打开,如果它被设置为阻塞模式——也就是说,setBlockOnOpen(true)曾被调用——它将进入事件循环,直到被关掉为止。

  在程序中使用ApplicationWindow,通常创建一个包含应用程序相关代码的子类继承它。许多ApplicationWindow的方法,以及它的父类Window的方法,都是protected的。你可以从继承的类中调用它们,也可以重载它们。比如,你为了给应用程序加一个菜单栏,可以在父亲Shell被创建之前调用protected的方法addMenuBar()——通常是在构造函数中。这个方法继而会调用protected的方法createMenuManager(),你可以重载它以创建适合这个程序的菜单。第十六章包含了关于创建菜单栏、工具条、CoolBar以及状态栏的更多信息。



关于WindowManager的一些话

  JFace包含一个叫WindowManager的类[2],它并不会控制窗口的外观,也不会管理用户和窗口的交互,而是将窗口编组,这样你就可以迭代的访问它们或者将它们整组的关闭。WindowManager的实例拥有窗口,也可以同时可选的拥有其他WindowManager的实例。WindowManager提供了两种构造函数,在表13-1中列出:

表13-1:WindowManager的构造函数  构造函数
描述

WindowManager()
构造一个根窗口管理器(也就是没有父亲的窗口管理器)

WindowManager(WindowManager parent)
构造一个窗口管理器,作为一个父亲窗口管理器的的孩子


  绝大多数WindowManager的方法只对它自己产生效果,除了close()方法会一连串影响到它所有的孩子WindowManger。表13-2列出了WindowManager的方法。

表13-2:WindowManager的方法  方法
描述

void add(Window window)
将window表示窗口添加到这个WindowManager中

boolean close()
关闭属于这个WindowManager的所有窗口,以及属于它所有孩子WindowManager的窗口。当任何一个窗口关闭失败时,停止关闭并且返回false,否则返回true

int getWindowCount()
返回属于这个WindowManager的窗口的数目

Window[] getWindows()
返回一个数组,其元素是属于这个WindowManager的所有的窗口

void remove(Window window)
将window表示的窗口从这个WindowManager中移去


  使用WindowManager时,构造一个实例,添加你的窗口,然后适当的调用它的方法。下面的代码创建了一个WindowManager,向里面加入了三个窗口,然后把它们全都关闭,如果关闭失败的话则打印一个诊断信息:

WindowManager wm = new WindowManager();
wm.add(windowOne);
wm.add(windowTwo);
if (!wm.close())
  System.err.println("Windows failed to close");




总结

  尽管刚刚解开JFace的面纱,你已经可以看出它的一些好处了[3]。通过对SWT一些细节的抽象,JFace允许你将注意力从“你的程序如何工作”转移到“你想要你的程序做什么”上。抽象是面向对象编程的中流砥柱,它的力量让程序开发更加简单。

  使用JFace要求和程序一起发布更多的库,别对此感到恼火。不管怎样,毕竟你将会从使用被测试过的代码中获得好处。它会加速你的开发周期并且减少错误出现的数目。

你可能感兴趣的:(eclipse,ant,jni,OS,osgi)