作者:梁祺 ([email protected])
来自:http://www.benisoft.net/day2/index.html
今天,我们看怎样创建一个View。在Eclipse里,用户通过View和Editor协同工作来完成任务。 Editor提供界面以完成任务的主要部分,以Eclipse提供的JDT(Java Development Tool)为例, 用户使用JDT来开发Java应用程序,所以很大一部分工作都是围绕编辑Java源程序,那么编辑工作就应该放在Editor里完成, 也就是Java Editor,JDT的其他View为Java应用程序的开发提供辅助,比如显示正在编辑的Java源程序所有的成员变量和方法。
首先来创建一个Plug-in项目,输入项目名”eclipse.tutorial.day2“。
输入Plug-in的ID,"eclipse.tutorial.day2"。
这次我们仍然选用Eclipse提供的例子模版,“Plug-in with a view”。 这个模版会生成一个名叫Sample View的View,包括右键快捷菜单,View工具栏,鼠标双击, 排序以及过滤。这个模版扩展了3个扩展点,我们会在后面一一介绍它们。
接下来是提供模版需要的信息。
- Java Package Name:Sample View所在的Java包名。
- View Class Name:Sample View的Java实现类名,就用缺省的SampleView。
- View Name:View的名字,“Sample View”。
- View Category ID:View类别的ID,Eclipse将属于同一个类别的View放在一起, 便于用户通过“Window/Show View/Others”查找某个View。
- View Category Name:View类别名。
- Select the viewer type:选择表格控件Table Viewer,我们明天会尝试Tree Viewer。
点击“Finish”按钮。
启动Eclipse,选择“Window/Show View/Other”。
在Show View对话框中找到Sample Category和Sample View。点击“Next”按钮。
我们在前面为Sample View选择了表格控件Table Viewer,这个表格有3行内容。
Sample View的表格能够接受鼠标双击事件,选择一行用鼠标双击,Sample View就会做出响应,弹出对话框。
Sample View实现了两个View工具栏按钮,点击右上角的工具栏按钮,Sample View弹出对话框“Action 1 executed”。
下面我们来看一下代码。在Package Explorer View里找到plug-in.xml双击, Plug-in Editor的Extensions子页显示这个Plug-in实现了3个扩展点。
首先是扩展点“org.eclipse.ui.views”,它是创建View所必须扩展的扩展点。 “Sample Category”定义了一个View的类别, ID为“eclipse.tutorial.day2”,名字为“Sample Category”。parentCategory留空。 通过parentCategory,我们可以将新的View类别设置为另一个View类别的子类,从而形成一个树状结构。
“Sample View”定义了一个View,ID为“eclipse.tutorial.day2.views.SampleView”, 名字为“Sample View”,模版为我们生成的Java类为“eclipse.tutorial.day2.views.SampleView”, category为前面定义的“eclipse.tutorial.day2”,还有图标。将鼠标移到class上, 我们可以看到View的Java类必须实现IViewPart接口。接下来我们看一下代码。
点击class,打开eclipse.tutorial.day2.views.SampleView。 它继承自ViewPart,一般情况View都是继承自这个虚类,这个虚类实现了IViewPart接口。 Sample View的ID作为常量定义在最前面,这是一个值得推荐的做法。 接下来定义了一个表格控件TableViewer的变量viewer,以及三个Action变量。
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = \ "eclipse.tutorial.day2.views.SampleView\";
private TableViewer viewer;
private Action action1;
private Action action2;
private Action doubleClickAction;
TableViewer来自于Eclipse提供的JFace, 它是对Eclipse的原生窗口控件库SWT的基于MVC(Model,View,和Controller)封装, 目的是为了避免在代码里将对窗口对象的操作代码和数据处理逻辑的代码混杂在一起,通过MVC模式,将两者隔离开, 便于理解和维护。这里,TableViewer就充当MVC Controller的角色,MVC View是它所封装的SWT窗口对象, MVC Model就是下面这个类ViewContentProvider。
TableViewer必须要求一个实现IStructuredContentProvider接口的类提供表格显示所需要的Java对象, 所以称为ContentProvider。我们这里看到的是最简单的实现,就是在getElements()直接返回所需要显示的对象数组, 数组的一个元素就是表格里的一行。这个例子的表格只有一列,一行内容就是一个字符串。如果表格内容复杂, 有很多列的话,就需要一个较复杂的数据对象来表示一行。
* The content provider class is responsible for
* providing objects to the view. It can wrap
* existing objects in adapters or simply return
* objects as-is. These objects may be sensitive
* to the current input of the view, or ignore
* it and always show the same content
* (like Task List, for example).
*/
class ViewContentProvider implements IStructuredContentProvider {
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
}
public void dispose() {
}
public Object[] getElements(Object parent) {
return new String[] { \ "One\", \ "Two\", \ "Three\" };
}
}
接下面的内部类ViewLabelProvider是告诉TableViewer如何显示一行的数据。 它必须实现ITableLabelProvider接口,一般我们会继承LabelProvider,让它提供一些缺省实现, 这样代码可以简洁一些。
public String getColumnText(Object obj, int index) {
return getText(obj);
}
public Image getColumnImage(Object obj, int index) {
return getImage(obj);
}
public Image getImage(Object obj) {
return PlatformUI.getWorkbench().
getSharedImages().getImage(ISharedImages.IMG_OBJ_ELEMENT);
}
}
下一个内部类是NameSorter,这个类非常简单,除了继承ViewerSorter,什么也没有做。 实际上,ViewerSorter包含一个文本比较器,所以我们删除NameSorter这个类,直接用ViewerSorter也行。
接着是SampleView的构造函数,这里本人曾经出过问题,创建的View在运行时怎么也找不到, 检查了很多地方,发现View没有实例化出来,最后才发现缺省构造函数不知道什么时候被加一个参数, 这样缺省构造函数就没了。 原因是Eclipse检查到Plug-in实现”org.eclipse.ui.views”这个扩展点后,它需要用反射实例化View对象的, 所以必须为它保留一个无参数的构造函数。
View的所有窗口控件的布局都必须在createPartControl()里完成,控件的布局我们会在以后讲到。 这里简单说一下这个例子是怎么做的。createPartControl()接受参数parent, 它是Eclipse为我们准备的摆放控件的容器,所以它的类型是Composite,TableViewer直接放在parent这个容器里, 所以TableViewer构造函数第一个参数必须输入它的父控件(也就是它的容器), 构造函数的第二个参数是TableViewer的风格,这里分别是允许多行选中(SWT.MULTI), 水平滚动条(SWT.H_SCROLL),垂直滚动条(SWT.V_SCROLL)。接着是实例化它的ContentProvider, LableProvider,和Sorter。最后这个viewer.setInput(getViewSite())可能有点令人费解, 设置TableViewer的输入为什么是View Site呢?其实你在这里除了null设任何东西都可以, 这和ContentProvider的实现有关,我们稍后介绍。接下来几个方法就直观一些了, 先给TableViewer关联一个联机帮助的ID,“eclipse.tutorial.day2.viewer”。 然后是makeActions()创建Action对象,接着hookContextMenu()创建右键菜单, hookDoubleClickAction()截获并处理TableViewer的双击事件, 最后contributeToActionBars()把Action添加到View的下拉菜单和工具栏上。
* This is a callback that will allow us
* to create the viewer and initialize it.
*/
public void createPartControl(Composite parent) {
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider( new ViewContentProvider());
viewer.setLabelProvider( new ViewLabelProvider());
viewer.setSorter( new NameSorter());
viewer.setInput(getViewSite());
// Create the help context id for the viewer's control
PlatformUI.getWorkbench().getHelpSystem().setHelp(viewer.getControl(),
"eclipse.tutorial.day2.viewer");
makeActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
}
我们前面提到,这个例子的ViewContentProvider的实现是最简单的做法, 它完全忽略input,所以它的inputChanged()的实现是空的。 通常的做法是将表格需要显示的对象通过viewer.setInput()交给TableViewer, TableViewer通知ContentProvider的inputChanged()方法,新的输入对象就是newInput参数, ContentProvider保存newInput的引用,在显示时, ContentProvider通过getElements()方法从newInput中获取对应到每一行的对象集合,返回给TableViewer显示。 这个例子在getElements()里直接写死需要返回的对象数组,所以input在这里就没有意义了,任何对象都可以使 getElements()返回写死的对象数组。
第二个实现的扩展点是“org.eclipse.ui.perspectiveExtensions”。通过这个扩展点, 我们将Sample View添加到Java Perspective。 Perspective将任务相关的Editor和View关联起来,用户切换Perspective将当前的View隐藏起来, 显示新任务相关的View。仍然以Java Perspective举例, Java Perspective由Outline View显示当前Java Editor显示的Java源程序结构, 比如成员变量,内部类,成员方法等等,Javadoc View显示Java源程序中光标所在的成员变量或方法的Javadoc, 等等。Plug-in Development Perspective用于Plug-in的配置, 它也有Outline View显示plug-in.xml的结构,显示扩展点等等。 但它没有Javadoc View,因为Javadoc View提供的功能和Plug-in的配置无关。在这个例子里, 我们假设Sample View对Java Perspective是有用的。首先加一个perspectiveExtension, 目标Java Perspective的ID是“org.eclipse.jdt.ui.JavaPerspective”。 为了给Java Perspective添加一个View,需要在perspectiveExtension下添加view, ID输入Sample View的ID,“eclipse.tutorial.day2.views.SampleView”,位置在Problem View的右侧。
最后实现的扩展点是“org.eclipse.help.contexts”,它和上下文帮助有关。 所谓上下文帮助就是允许用户通过F1键获取焦点所在控件的帮助信息。这个例子为TableViewer建立一个上下文帮助, 所以只要焦点在TableViewer上,按F1键就能获得TableViewer的帮助信息。首先定义contexts, 指定一个XML文件,这个文件包含了上下文帮助的内容。如果该文件来自其他Plug-in, 可以在plugin这栏里输入该Plug-in的ID。至于上下文帮助及其XML文件,我们留到后面和帮助一起介绍。
如果希望从一个现有的Plug-in项目中新建View,在Plug-in Editor的Extensions页,点击”Add“按钮, 在对话框中输入”views“,找到扩展点”org.eclipse.ui.views“,并选中, 我们就会看到刚刚介绍过的模板Sample View。一般都会使用Sample View来创建View的骨架,删除掉不需要的代码, 这样会简单一点。
到这里,我们了解了怎么创建一个View,怎么创建TableViewer, 使用Content Provider和Label Provider在表格里显示数据, 以及怎么将View通过Perspective扩展点将View关联到其他Perspective。