户在打开那个数据导入窗口, 单击【导入】按钮后就切换到另外一个窗口进行录单操作了。天呀,如果没有提供那个进度条的功能,那么 用户单击【导入】按钮以后整个 ERP 系统就“死掉了” ,用户就无法进行任何操作,也就无法做任何工作, 难道这半个多小时要他去上网聊 QQ、翻纸牌吗? 在这一点上 Eclipse 做的无疑是非常好的。当我们新建一个项目的时候,如果项目的初始化时间比较长, Eclipse 就会弹出一个带滚动条的窗口,提示用户正在初始化;对于一些耗时非常长的操作,比如从 CVS 检 出代码,Eclipse 会弹出一个带有【在后台运行】按钮的进度对话框,如图 3.3 所示,用户单击【在后台运行】 按钮以后,这个对话框就会关闭,这样用户就可以在 Eclipse 中进行其他的操作了,避免了长时间等待所造成 的时间浪费。
图 3.3
进度条
我们最常接触的就是 IProgressMonitor 了, 在很多方法中都要求传递此接口的实例, 比如编辑器的 doSave 方法就是如下声明的:
public void doSave(IProgressMonitor monitor)
通过这个接口就可以操控进度条来显示我们当前的保存进度了。不过 IProgressMonitor 并不是进度条对 话框,它要“依靠”一个进度显示器来把进度显示出来,比如最常见的进度对话框 ProgressMonitorDialog。 部分任务在运行的时候可以由用户选择取消,当用户取消任务的时候,IProgressMonitor 的 isCanceled 方 法会返回 true,因此我们在任务进行的时候要实时地去调用 isCanceled 方法,当发现任务被取消的时候要尽 快结束任务。 我们可以使用 Java 的标准接口 Runnable 来实现多线程任务运行,不过在 Eclipse 中又有了新的选择,那 就是 IRunnableWithProgress,其声明如下:
public interface IRunnableWithProgress { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException; }
这个类的使用和 Runnable 非常相似, 只要把任务放到 run 方法中就可以了, 最重要的是可以调用 monitor 来对当前进度显示进行控制。下面就是一个完整的进度条演示例子。
ProgressMonitorDialog dialog = new ProgressMonitorDialog(shell); dialog.run(true, true, new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { final int ticks = 10000; monitor.beginTask("开始操作", ticks); try { for (int i = 0; i < ticks; i++) { if (monitor.isCanceled()) throw new InterruptedException(); monitor.worked(1); } } finally { monitor.done(); } } });
调用 beginTask 方法来完成任务,ticks 参数表示此任务有多少工作量,调用 worked 方法报告自上次报告 以来当前完成的任务数量,在循环中不断通过 isCanceled 方法判断当前任务是否被用户取消。需要注意,要 在 finally 中调用 done 方法完成任务,否则会出现进度对话框无法正常关闭的情况。 除了 ProgressMonitorDialog 外, Eclipse 中还可以通过其他方式显示进度, 在 比如 IWorkbenchWindow 通 过在工作台窗口的状态行中显示进度来实现此界面,WizardDialog 在向导状态行中显示长时间运行的操作。
除了可以自己构造进度对话框来显示进度之外, 我们还可以调用平台的进度服务, 而且 Eclipse 也推荐使 用平台的进度服务,这样可以使所有插件都将具有一致的进度表示。平台的进度服务定义为接口 IProgressService,我们可以通过 PlatformUI.getWorkbench(). getProgressService 方法来调用系统的进度服务, 例如: IProgressService progressService = PlatformUI.getWorkbench() .getProgressService(); progressService.busyCursorWhile(new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { //执行耗时的操作 } });
在调用 Eclipse 的方法或者第三方插件的一些方法的时候, 有的方法要求传递一个实现了 IProgressMonitor 的 实 例 进 去 , 如 果 我 们 无 法 传 递 或 者 无 需 传 递 的 时 候 , 最 好 不 要 传 递 null 值 进 去 , 而 是 要 传 递 NullProgressMonitor 的一个实例进去,此类位于 org.eclipse.core.runtime 包下,它实现了 IProgressMonitor 接 口,但是所有方法都是给的空实现,传递此类就避
免了被调用方法没有进行空指针判断而造成的麻烦。
3.4 对 话
框
3.4.1 信息提示框
信息提示框对应的类为 org.eclipse.jface.dialogs.MessageDialog,它定义了如下主要方法。 (1) 确认对话框(如图 3.4 所示):
public static boolean openConfirm(Shell parent, String title, String message)
图 3.4
确认对话框
(2) 错误信息框:
public static void openError(Shell parent, String title, String message)
(3) 普通消息框:
public static void openInformation(Shell parent, String title, String message)
(4) 询问对话框(如图 3.5 所示):
public static boolean openQuestion(Shell parent, String title, String message)
图 3.5
询问对话框
注意询问对话框与确认对话框方法的区别。 (5) 警告对话框:
public static void openWarning(Shell parent, String title, String message)
3.4.2 值输入对话框
在和用户交互的时候,对于一些复杂的信息,可能需要通过自定义的对话框进行采集,而对于像简单的 字符串之类的信息,则可以通过弹出值输入对话框的方式进行采集。 值输入对话框定义在 org.eclipse.jface.dialogs.InputDialog 中,与消息对话框不同,这个类是必须实例化才 能使用的,其构造函数为:
public InputDialog(Shell parentShell, String dialogTitle, String dialogMessage, String initialValue, IInputValidator validator)
参数 dialogTitle 为标题,dialogMessage 为显示的消息,initialValue 为对话框中的初始值,validator 为值 校验器。当 validator 为 null 的时候,不对对话框中的值做校验,而非 null 的时候需要做校验。 IInputValidator 接口定义如下:
public interface IInputValidator { public String isValid(String newText); }
当 isValid 返回非空的时候,值校验不通过,并且把 isValid 返回的值作为错误信息显示。 使用值输入对话框的例子如下:
InputDialog inputDlg = new InputDialog(shell,"输入","请输入您的年龄","20", new IInputValidator(){ public String isValid(String newText) { int i; try { i = Integer.parseInt(newText); } catch (NumberFormatException e) { return "年龄必须为整数!"; }
if(i<0) { return "兄弟来自反物质世界?年龄不可能为负吧!"; }
if(i>150) { return "您也太高寿了吧!"; }
return null; } });
if(inputDlg.open()==Window.OK) {
System.out.println(inputDlg.getValue()); }
运行以后当在对话框中输入“-20”的时候就会提示错误,如图 3.6 所示。
图 3.6
输入对话框
3.4.3 错误对话框
错误对话框定义在 org.eclipse.jface.dialogs.ErrorDialog 中,它有两个重载的 openError 静态方法,与其他 对话框不同的是有一个 IStatus status 参数,这个参数用来设置错误信息,一般我们使用它的一个实现类 org.eclipse.core.runtime. Status,Status 中定义了两个静态常量 OK_STATUS、CANCEL_STATUS,我们可以使 用它们,如果它们不能满足要求,就要调用 Status 的构造函数进行实例化,其构造函数如下:
public Status(int severity, String pluginId, int code, String message, Throwable exception) l l l l
severity 表示错误的程度,可取值为 OK、ERROR、INFO、WARNING、CANCEL。 pluginId 为调用插件的插件 id,一般定义在对应插件的 Activator 中。 code 为错误代码。 message 为错误消息。
l exception 为要抛出的异常。 显示效果如图 3.7 所示。
图 3.7
错误对话框
3.4.4 颜选择对话框
颜选择对话框定义在 org.eclipse.swt.widgets.ColorDialog 中,其调用方法与普通对话框没有什么不同。 例如:
ColorDialog colorDlg = new ColorDialog(shell); RGB rgb = colorDlg.open(); if(rgb!=null) { Color color = null; try { color = new Color(shell.getDisplay(),rgb);
//使用 color…… } finally { if(color!=null) color.dispose(); } }
这里得到返回值的方式非常值得研究,对话框并没有直接返回 Color,而是返回一个 RGB 对象的实例, 由调用者来根据 RGB 构造 Color,这正好符合了 SWT 中资源管理的一个原则: “谁创建谁销毁” 。如果 ColorDialog 返回值是 Color 类
型,那么必须由 ColorDialog 负责销毁,可是 ColorDialog 不知道什么时候去销 毁,所以 ColorDialog 就返回了一个由 JVM 去负责销毁的对象 RGB,此对象包含了需要的信息,由调用者去 构造,类似的用法在下面的字体对话框中也可以看到。 ColorDialog 还有一个 setRGB 方法可以用来给颜对话框设置初始值。
3.4.5 字体对话框
字体对话框定义在 org.eclipse.swt.widgets.FontDialog 中,调用方法如下: FontDialog fontDlg = new FontDialog(shell); FontData fontData = fontDlg.open(); if(fontData!=null) { Font font = null; try { font = new Font(shell.getDisplay(),fontData); //使用 font…… } finally { if(font!=null) font.dispose(); } }
和颜对话框类似,字体对话框返回的字体信息是保存在由 JVM 负责资源回收的 FontData 对象中的, 由调用者来根据 FontData 对象构造字体对象。FontDialog 有一个 setFontList 方法可以用来设置初始值。
3.4.6 目录选择对话框
目录选择对话框定义在 org.eclipse.swt.widgets.DirectoryDialog 中,调用方法如下:
DirectoryDialog dirDlg = new DirectoryDialog(shell); String dir = dirDlg.open(); if(dir!=null) { System.out.println(dir); }
DirectoryDialog 中定义了如下几个方法。
l l l
setText:为对话框设置窗口标题。 setMessage:为对话框设置提示信息。
eclipse开发手机app setFilterPath:为对话框设置初始路径。 下面的代码执行以后的效果如图 3.8 所示。
DirectoryDialog dirDlg = new DirectoryDialog(shell); dirDlg.setText("这里是 Text"); dirDlg
.setMessage("这里是 Message"); dirDlg.setFilterPath("c:/Downloads"); String dir = dirDlg.open();
图 3.8
目录选择对话框
3.4.7 文件选择对话框
与 .Net、Delphi、VB 等框架中的文件对话框不同,SWT 中的保存对话框和打开对话框都定义在 org.eclipse.swt.widgets.FileDialog 类中,只要在构造函数中指定不同的风格即可。 打开对话框:
FileDialog fileDlg = new FileDialog(shell,SWT.OPEN);
保存对话框:
FileDialog fileDlg = new FileDialog(shell,SWT.SAVE);
FileDialog 中定义了如下几个方法。
l l l l l
setFileName:设定初始文件名。 setFilterExtensions:设定文件名过滤器。 setFilterPath:设定初始路径。 setText:设定对话框标题。 getFileNames:以数组形式返回选中的多个文件名。
l getFilterPath:返回选中的路径。 调用例子: FileDialog fileDlg = new FileDialog(shell,SWT.OPEN|SWT.MULTI); fileDlg.setFilterExtensions(new String[]{"*.mp3","*.wmv","*.rm"}); fileDlg.setFilterPath("F:/资料/My Music"); fileDlg.setText("请选择要打开的音乐文件(支持多选)"); String filePath = fileDlg.open(); if(filePath!=null) { System.out.println("路径:"+fileDlg.getFilterPath()); String[] files = fileDlg.getFileNames(); for(int i=0,n=files.length;i<n;i++) { System.out.println(files[i]); } }
3.4.8 自定义对话框及配置保存与加载
程序中经常会需要一些自定义对话框,我们可以从 SWT 的 Dialog 类(位于包 org.eclipse. swt.widgets 中) 派生,也可以从 JFace 的 Dialog(位于包 org.eclipse.jface.dialogs 中)中派生。建议我们如果没有特别的需要最 好从 JFace 的 Dialog 继承,因为它提供了更多 SWT 对话框中没有提供的功能。 我们经常需要保存对话框中的值,并在下次打开的时候重新加载。可以自己通过读写配置文件方式完成 此功能,不过 Eclipse 提供了更好的功能,那就是使用对话框配置服务。对话框值的保存与加载的核心类就是 org.eclipse.jface.dialogs 包下的 IDialogSettings,它可以用来保存和检索与键名相关联的基本数据类型和字符 串值。 每 个 插 件 都 有 自 己 的 Activator , 这 些 Activator 的 基 类 就 是 AbstractUIPlugin , 我 们 可 以 通 过 AbstractUIPlugin 的 getDialogSettings 方法来取得此插件对应的对话框配置服务,此服务并不是只有在对话框 中才能调用,我们可以在插件代码中的任何位置访问对话框设置。取得服务的方式非常简单:
IDialogSettings settings = Activator.getDefault().getDialogSettings();
配置中的值是使用 get 和 put 方法来存储和检索的,可以存储和加载布尔、长型、双精度、浮点、整 型、数组和字符串值。以下代码段说明可以如何使用对话框设置来初始化对话框中的控件值:
protected Control createDialogArea(Composite parent) { IDialogSettings settings = Activator.getDefault().getDialogSettings(); checkbox.setSelection(settings.getBoolean("isOpenWhenLoad")); }
单击【确定】按钮时,就可以存储设置值:
protected void okPressed() { IDialogSettings settings = Activator.getDefault().getDialogSettings(); settings.put("isOpenWhenLoad", checkbox.getSelection()); super.okPressed(); }
3.5 首 选
项
Eclipse 中的首选项是整个 Eclipse 的配置中心,插件的主要配置都在这个地方完成。首选项也是可以定 制的,也就是说我们可以将我们自己的首选项页面加入这个首选项对话框中。 Eclipse 中提供了一个首选项开发的向导,我们可以通过这个向导生成的代码来理解首选项的开发。 这里重点讲解一下首选项的配置保存。 org.ec
lipse.core.runtime.preferences 包提供了用于访问首选项的类。 与上面讲解的对话框配置保存一样,插件首选项也是以键值对的形式保存的,其中键描述首选项的名称,而 值必须是几种不同类型中的一种(boolean、double、float、int、long 或 string)。 通过 AbstractUIPlugin 的 getPreferenceStore 方法可以取得首选项配置服务。 读取:
IPreferenceStore store = getPreferenceStore(); checkBox1.setSelection(store.getBoolean("isLoad"));
保存:
IPreferenceStore store = getPreferenceStore(); store.setValue("isLoad", checkBox1.getSelection());
首选项页都直接或者间接地从 PreferencePage 类继承,在初始化的时候需要首先调用 setPreferenceStore 方法为此页设定一个首选项配置服务,当【应用】 【取消】 【默认值】或【确定】按钮被单击的时候, 、 、 performApply、performCancel、performDefaults、performOk 方法将会分别被调用,我们就可以在这些方法中 保存配置,而在 createContents 中构造控件的时候去加载这些参数。 如果我们要自己编写首选项配置界面的话,不仅要处理页面布局,还要自己处理属性的保存、加载,幸 好 Eclipse 为我们提供了一个更好用的配置界面基类 FieldEditorPreferencePage。 FieldEditorPreferencePage 将每 一个配置项看成一个字段编辑器,整个页面就是由不同类型的字段编辑器组成的。FieldEditorPreferencePage 提供了常见字段编辑器:
l l l l l l l l l
BooleanFieldEditor——布尔字段编辑器。 IntegerFieldEditor——整数编辑器,可调用 setValidRange 来限制整数的范围。 StringFieldEditor——文本编辑器,可以调用 setEmptyStringAllowed 来限制是否能为空。 RadioGroupFieldEditor——单选按钮组编辑器。 ColorFieldEditor——颜编辑器。 FontFieldEditor——字体编辑器。 DirectoryFieldEditor——文件夹编辑器。 FileFieldEditor——文件编辑器。
ScaleFieldEditor——步进范围整数编辑器。 各个插件还可以从 FieldEditor 继承来编写符合自己个性化要求的字段编辑器, 3.9 是一个字段编辑器页 图 面的典型应用。 Eclipse 的插件开发中“首选项向导”生成的就是基于 FieldEditorPreferencePage 的代码,可以仔细研究一 下。
图 3.9
字段编辑器示例
首先看 SamplePreferencePage.java:
public class SamplePreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { public SamplePreferencePage() { super(GRID); setPreferenceStore(Activator.getDefault().getPreferenceStore()); } public void createFieldEditors() { addField(new DirectoryFieldEditor(PreferenceConstants.P_PATH, "&Directory preference:", getFieldEditorParent())); addField(new BooleanFieldEditor(PreferenceConstants.P_BOOLEAN, "&An example of a boolean preference", getFieldEditorParent())); addField(new RadioGroupFieldEditor(PreferenceConstants.P_CHOICE, "An example of a multiple-choice preference", 1, new String[][] { { "&Choice 1", "choice1" }, { "C&hoice 2", "choice2" } }, getFieldEditorParent())); addField(new StringFieldEditor(Prefere
nceConstants.P_STRING, "A &text preference:", getFieldEditorParent())); } public void init(IWorkbench workbench) { } }
我们需要做的只是在构造函数中给它传递一个首选项配置存取接口并在 createFieldEditors 方法中调用 addField 方法添加各种各样的编辑器,其他的事情根本无需我们处理。图 3.10 是运行效果图。
图 3.10
示例首选项页
插件代码还生成了一个初始化类,用来设置页面的默认值:
public class PreferenceInitializer extends AbstractPreferenceInitializer { public void initializeDefaultPreferences() { IPreferenceStore store = Activator.getDefault().getPreferenceStore(); store.setDefault(PreferenceCo
nstants.P_BOOLEAN, true); store.setDefault(PreferenceConstants.P_CHOICE, "choice2"); store.setDefault(PreferenceConstants.P_STRING, "Default value"); } }
如果您的首选项页面非常复杂的话,可能只使用 addField 添加简单的编辑器解决不了问题,您可以直接 使用 SWT 代码来对首选项页进行更精细化、更复杂的调整。
3.6 Eclipse 资源 API 和文件系统
说到 Eclipse 中与资源相关的最重要的概念就是:工作空间、项目、文件夹和文件。工作空间的资源组织 成树结构,项目位于顶部,而文件夹和文件在下面。特殊资源、工作空间根目录资源充当资源树的根目录。 工作空间可以有任意数目的项目,每个项目都可以存储在磁盘上的不同位置。工作空间负责管理用户资源, 组织一个或多个顶级项目。每个项目对应于工作空间目录中的子目录。每个项目都可以包含文件和文件夹。 图 3.11 是项目中不同资源的示意图。
图 3.11
项目中的不同资源
相信上图我们大部分都能看懂,需要注意的是 Java 工程中的包、源文件夹、普通文件夹在 Eclipse 资源 这一个层次看起来都属于文件夹,它们的不同其实是由 JDT 来标识和区分的。 工作空间下可能有一个 .metadata 目录,它是一个特殊的文件夹,其中存储的是工作空间相关的配置文 件,我们不能使用一般文件系统 API 来编辑或处理这些文件。与此相似的就是每个项目目录下的 .project。 工作空间、项目、文件夹、文件对应的类型接口分别为 IWorkspace、IProject、IFolder、IFile。资源相关 的接口都继承了 IResource 接口, 由于工作空间并不只是资源的管理者, 因此 IWorkspace 并没有继承 IResource 接口,为了将工作空间作为资源的管理者这一功能体现出来,抽象出了 IWorkspaceRoot 的接口(即工作空间 根目录),通过 IWorkspace 的 getRoot 就可以得到对应的工作空间根目录。由于工作空间根目录、项目、文件 夹都是可以容纳其他资源的, 因此为它们抽取了一个基类接口 IContainer。 3.12 为 Eclipse 中资源相关类的 图 继承结构图。
图 3.12
资源的继承结构图
3.6.1 资源相关接口的常见方法
为了方便地到有用的方法,这里我们简单介绍一下资源相关接口的常见方法。 (1) IResource
l l
delete:删除此资源。 getFileExtension:返回文件的扩展名。
l l l
getFullPath:返回此资源相对于工作空间根目录的相对路径,返回值类型是 IPath。 getLocation:返回此资源在文件系统中的绝对路径,返回值类型是 IPath。 exists:判断此资源是否存在。处理资源与使用 Java.io.File 处理文件非常相似。IResource 只是一个 句柄。当调用像 getProject、getFolder 这样的方法时,会将句柄返回给资源,即使指定的资源并不 存在。因此在必要的时候要使用 exists 方法来确定资源是否存在。
l l l l l
getParent:得到父资源容器,返回值类型为 IContainer。 getProject:返回此资源所属的项目,返回值类型为 IProject。 getProjectR
elativePath:返回此资源在项目中的相对路径,返回值类型是 IPath。 getWorkspace:返回此资源所属的工作空间,返回值类型为 IWorkspace。 isSynchronized:判断资源是否与文件系统同步。 exists(IPath path):判断指定的路径 path 是否在本容器内存在。 findMember:返回指定路径的资源,返回值类型为 IResource。 getDefaultCharset:返回此容器内资源的默认编码。 getFile:返回指定路径的文件,返回值类型为 IFile。 g
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论