[转载]在 Eclipse Workbench 之外使用 Eclipse GUI,第 2 部分: 使用 JFace 图像注册
在 Eclipse Workbench 之外使用 Eclipse GUI,第 2 部分: 使用 JFace 图像注册表
在本文中,A. O. Van Emmenis 继续研究在第 1 部分中着手构建的示例。他将完善内容提供程序和标签提供程序,并演示如何在 JFace 查看器中使用排序和过滤。他将演示如何给窗口添加状态行,给两个查看器添加图标,并讨论如何通过使用 JFace 图像注册表来节省系统资源。
在本系列的 第 1 部分中, 我着手构建了一个示例,该示例将 JFace 应用程序窗口子类化并且使用树查看器和表查看器来显示文件夹和文件。这次,我们将完成上个示例的收尾工作,然后给窗口添加一条状态行。我们要做的较大更改 是给两个查看器添加图标,并了解 JFace 图像注册表。最后,我们将对查看器进行排序和过滤,以获得一个更加真实的“文件资源管理器”样式。
如果要下载本文中 示例的源代码,请注意我的系统设置:
- Windows 2000
- Eclipse,稳定构建版 M3(2002 年 11 月 15 日)
- Eclipse 安装在 C:eclipse-2.1.0 中
请您自行完成随后所有调整名称和文件分隔符的工作,以便程序能在您的系统上正确地运行。
请确保以下 jar 文件位于类路径上:
C:eclipse-2.1.0pluginsorg.eclipse.jface_2.1.0jface.jar
C:eclipse-2.1.0pluginsorg.eclipse.runtime_2.1.0
untime.jar
C:eclipse-2.1.0pluginsorg.eclipse.swt.win32_2.1.0wswin32swt.jar
C:eclipse-2.1.0pluginsorg.eclipse.ui.workbench_2.1.0workbench.jar
C:eclipse-2.1.0pluginsorg.eclipse.core.runtime_2.1.0
untime.jar
为确保 Java VM 能找到您在运行时所用 GUI 的正确共享库,请使用以下参数运行 Java VM:
-Djava.library.path=C:eclipse-2.1.0pluginsorg.eclipse.swt.win32_2.1.0oswin32x86
最后,请从包含 icons文件夹的文件夹中运行这些程序,以便示例能找到包含图标的 gif 文件。
|
|
上一篇文章结束时,我们的资源管理器应用程序如图 1 所示:
图 1. 资源管理器(V4)
我们在最左边窗格中使用树查看器显示文件夹和文件。当在左边窗格中选中某个文件夹时,它所包含的文件就显示在最右边窗格的表查看器中。让我们通过设置窗口标题来着手完善这个示例。
|
|
这是 JFace 不试图向您隐藏 SWT 的又一个例子。必须获取底层 SWT Shell 窗口小部件并设置其标题。
我们使用 getShell() 向 JFace 窗口求取其 SWT shell,然后使用 setText() 设置 shell 的标题,于是,在资源管理器 createContents() 方法中,我们将使用如下语句:
getShell().setText("JFace File Explorer");
我们在表视图中有了一列。让我们添加另一个以字节为单位显示文件大小的列。我们将使该列中的文本向右对齐。它的代码与第一列类似,所以我不在这里显示。
既然有了两列,那就把表查看器的选择样式设置为 FULL ,表示选中某行后,整行都将被突出显示。
new TableViewer(sash_form, SWT.BORDER | SWT.FULL_SELECTION);
|
|
|
状态行是应用程序窗口的另一个可选组件。必须通过使用 addStatusLine() ,在窗口创建 SWT 窗口小部件之前要求窗口创建状态行。
让我们用状态行显示在表视图中选中了多少项。每当表视图中的选择发生改变时,我们就更新状态行并显示有多少项被选中,如清单 1 所示:
清单 1. 资源管理器 — 设置状态行中的文本tbv.addSelectionChangedListener(new ISelectionChangedListener() |
缺省情况下,表查看器被设置为单选方式。可以通过在创建表查看器时将多选方式作为样式参数的另一位(以文字表示)添加,将表查看器更改为多选方式。
new TableViewer(sash_form, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI);
综合以上代码就得到清单 2:
清单 2. 资源管理器(V5)import java.io.*; |
运行该程序的结果如图 2 所示:
图 2. 资源管理器(V5)
如您所见,size 列目前不正确 — 我们马上就修正它。
|
|
在 SWT 中,用来表示图标的对象是 Image (有关类 Image 的详细信息,请参阅本文后面的 参考资料)。当直接创建可显示图像的 SWT 窗口小部件时,可使用 setImage(Image) 设置它。
关于图像有一个问题:它们是受限资源。图像是比较重量级的对象,具有对外部 OS 资源的引用(图 3)。在某些操作系统上,对任一时间内可拥有图像的数量有严格限制,因此使用它们时必须注意这一限制。
图 3. 操作系统中的图像描述符、图像和资源
最 终,当应用程序退出时,会释放 Image 所用的资源 — 但即使那样,在某些操作系统上仍可能有问题:共享库造成资源被继续占用。出于各种原因,不能指望 Java 垃圾收集器会替您清理它们。有关标准窗口小部件工具箱(Standard Widget Toolkit)的完整说明,请参阅 参考资料。
有个好消息:图像 可以在窗口小部件之间共享,而且 SWT 为 Image 提供了 dispose() 方法,它可以释放图像所用的资源。
因 为窗口小部件可以共享图像,所以 SWT 做出了这样的设计决定:当窗口小部件不再存在时(也就是说,在关闭窗口时),SWT 将不会自动清除这些图像。然而,JFace 会给予您一些帮助,它告诉您大型 UI 对象(如窗口和查看器)何时可以清除它们的图像,然后由您负责清除已创建的任何图像。
实际上,绝大多数应用程序都从文件或数据库获取其图标,这些文件或数据库包含一些标准格式(如 gif 或 jpeg)的数据。为此,JFace 提供了 ImageDescriptor (请参阅 参考资料),这是一个轻量级对象,它不存储图像本身,而是可以按需要创建特定的图像。这个类有许多可以从不同来源构造图像的子类。
在本例中,我们将图标存储在位于
icons 文件夹的 .gif 文件中,因此我们将在
ImageDescriptor 中使用这一工厂(factory)方法:
public static ImageDescriptor createFromURL(URL url)
public Image getColumnImage(Object element, int columnIndex)
为了便于我们管理图像的共享和清除,我们将使用 ImageRegistry (请参阅 参考资料)。
|
|
管理一组共享且昂贵的资源是经典的软件工程问题。JFace 提供经典的解决方案:一个能高速缓存图像和图像描述符的*共享注册表。
其思想是:您的代码获取它需要的图像描述符,然后将其添加到图像注册表,并使用键为每个图像描述符建立索引。当希望获得图像时,就用它的键从注册表中访存。
当清除*显示(Display)时,图像注册表将负责清除它的图像。如果需要更频繁地清除图像,则可能要创建数个图像注册表,并按需要直接清除图像。要获得更多的详细信息,请参阅 Eclipse 网站上关于使用图像的文章(请参阅 参考资料)以获得链接。
我们的小示例将只使用少数几个图标,因此我们将使用单个图像注册表。让我们先看看表查看器。
要从名为 iconsfile.gif 的文件创建图像描述符,可使用以下语句:
image_descriptor = ImageDescriptor.createFromURL(new URL("icons/file.gif"));
获得图像描述符之后,可将它存储在图像注册表中。在本例中,我们使用字符串“file”作为键:
image_registry.put("file", image_descriptor);
然后,要再次获取该图像,可使用以下语句:
image = image_registry.get("file");
URL 的构造函数抛出一个已检查异常(checked exception)。我们要使用的所有 URL 都将是硬编码的,因此我们将把 URL 的创建包装在某个工具代码中,以将已检查异常转换为运行时异常。
另外,我们希望在代码*享这些图像,因此需要集中创建图像注册表,并使它可被全局访问。
现在该创建一个实用程序类了,如清单 3 所示:
清单 3. Util(V1)import java.net.*; |
getImageRegistry() 方法简单地创建了一个图像注册表并添加了两个图像描述符。我们现在需要更改 FileTableLabelProvider 以根据元素是文件还是文件夹来返回正确的图像,如清单 4 所示:
清单 4. FileTableLabelProvider(V2)import java.io.*; |
由于现在表有两列(我们在前面添加了大小(size)列),所以还必须调整 getColumnText(Object,int) 以使程序正确工作。
运行该程序的结果如图 4 所示:
图 4. 资源管理器(V6)
程序开始变得十分漂亮了 — 至少在表查看器中是这样。让我们升级 FileTreeLabelProvider 以使用图像,如清单 5 所示:
清单 5. FileTreeLabelProvider(V2)import java.io.*; |
运行该程序的结果如图 5 所示:
图 5. 资源管理器(V7)
现在,可以很容易地看出文件和文件夹之间的区别,我们还可以看到:在表视图中,缺省排序算法按字母顺序给各项排序 — 但将文件夹和文件混在一起。您可能还注意到:在树视图中,我们同时看到了文件夹 和文件。我们现在来修正这个问题。
|
|
要在查看器中对项进行排序,我们使用 ViewerSorter 。
ViewerSorter (请参阅 参考资料)是旨在被子类化的类。查看器使用查看器排序程序以便采取两个步骤对它的元素排序。首先,它询问元素的 类别(category)。这返回一个整数,然后它把元素按其 类别号的升序归到各类别组:
public int category(Object element)
接着,在每个类别中,它使用 ViewerSorter 的 compare() 方法进行排序。该方法类似于标准 Java 类 Comparator 中的 compare() 方法:
public int compare(Viewer viewer, Object element1, Object element2)
缺省情况下,使用标签提供程序返回的字符串并忽略大小写进行排序。
我们在表查看器中只实现 category 方法,如清单 6 所示:
清单 6. FileSorter(V1)import java.io.*; |
这将先对文件夹排序,再对文件排序。
在树查看器中,我们希望只显示文件夹。我们通过使用 ViewerFilter (请参阅 参考资料)做到这一点。和排序程序一样,过滤器也旨在被子类化。我们需要实现 select() 方法,它检查元素,如果将要显示该元素,则返回 true。在本例中,我们希望只允许文件夹通过过滤器,所以有清单 7 中的 AllowOnlyFoldersFilter() 方法:
清单 7. AllowOnlyFoldersFilter(V1)import java.io.*; |
注:我们过滤的元素是第 3 个参数。现在给出了查看器和父元素 — 以便在需要时访问它们。
现在,我们只需将这些类的实例附加到查看器,如清单 8 所示:
清单 8. 资源管理器(V8)import java.io.*; |
注:正如这些方法的名称所表明的那样,一个查看器可以同时有多个过滤器,但只能有一个排序程序。
现在运行资源管理器所得的结果如图 6 所示:
图 6. 资源管理器(V8)
|
|
好了,这些图标无疑使程序更漂亮了一些。我们有了窗口标题,它告诉我们看到的是什么,还有一个新的漂亮的状态行,它告诉我们选中了多少项,再通过过滤和排序将文件和文件夹整齐地分隔开,这个程序开始象一个真正的文件资源管理器了。
它可能看起来漂亮了一点,但现在还做不了什么。在本系列(由 3 部分组成)的最后一篇文章中,我们将通过添加菜单和操作来弥补这一缺陷。我们将了解如何创建菜单栏、工具栏和弹出菜单。我们还将开发一些示例,这些示例中 的菜单会使用一些巧妙的 JFace 实用程序来启动程序并访问系统剪贴板,而且我们还将演示如何使用侦听器使菜单项对上下文敏感。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-130658/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/374079/viewspace-130658/