eclipse插件开发入门及常用组件要点
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Eclipse插件开发入门.
Eclipse最有魅力的地方就是它的插件体系结构。
在这个体系中重要的概念是扩展点(extension points)。
扩展点就是在软件开发过程中暴露出来的接口。
每一个插件都是在现有的扩展点上开发的,并可能还留有自己的扩展点,以便在这个插件上继续开发。
简介
Eclipse 平台是IBM向开发源码社区捐赠的开发框架,它之所以出名并不是因为IBM宣称投入开发的资金总数为4 000万美元,而是因为如此巨大的投入所带来的成果:一个成熟的、精心设计的、可扩展的体系结构。
Eclipse 的价值是它为创建可扩展的集成开发环境提供了一个开放源码平台。
这个平台允许任何人构建与环境和其他工具无缝集成的工具。
工具与Eclipse无缝集成的关键是插件。
除了小型的运行时内核之外,Eclipse中的所有东西都是插件。
从这个角度来讲,所有功能部件都是以同等的方式创建的。
由于有了插件,Eclipse系统的核心部分在启动时要完成的工作十分简单:启动平台的基础部分和查找系统的插件。
整个Eclipse体系结构就像一个大拼图,可以不断地向上加插件,同时,在现有插件上还可以再加插件。
开发“Hello,world”插件
创建插件最简单的方法是使用Eclipse中专门为开发插件而设计的插件PDE(Plug-in Development Environment)。
PDE 和 Java Development Tooling(JDT)IDE是 Eclipse 的标准扩展。
PDE 提供了一些向导可以帮助创建插件。
下面的“Hello,world”插件将通过PDE进行开发。
下面是创建一个简单插件的操作步骤。
(1)运行Eclipse。
单击Eclipse的“File”→“New”→“Other”菜单项,在弹出的对话框中选择Select对话框左边的Plug-in Development向导。
如图1所示,选择Plug-in Project。
图1 新建插件对话框
(2)单击“Next”按钮,弹出新建对话框,输入项目名称。
此处使用了
“com.test.helloworld”。
单击“Next”按钮后弹出新建对话框页,如图2所示,插件标识就与项目名称相同。
使用项目名称作为插件标识可以将该插件与另一个插件的名称发生冲突的机会减到最小。
图2 新建对话框向导
(3)单击“Next”按钮,选择“Hello, world”,如图3所示。
图3 新建插件向导
(4)单击“Finish”按钮,就可以创建用户想要建立的插件。
上例中通过插件创建向导创建了“Hello,world插件”,通过Eclipse的插件创建向导还能够创建其它扩展点插件的创建。
调试“Hello,world”插件
通过PDE不但能创建插件,还能够调试插件。
在Eclipse中调试插件的步骤如下。
(1)单击“Run”→“Debug”菜单项。
(2)在弹出的对话框窗口中用鼠标右键单击“Eclipse Application”选项。
(3)单击“New”菜单项(或双击Eclipse Application树节点),创建调试插件配置参数对话框,并通过对话框设置插件的调试参数,如图4所示。
图4 Debug环境参数设置
(4)单击“Debug”按钮。
现在已经启动了一个调试的Eclipse,可以看到图5显示的调试窗口。
调试窗口多了一个“Sample Menu”菜单项,工具栏多了一个按钮,单击菜单或按钮将会弹出“Hello,world”对话框。
图5 “Hello,world”插件效果图
用户可以在程序中可执行到的位置设置断点,就可以和调试Java程序一样调试Eclipse 插件了。
注意:如果在图4中选择Clear workspace data before lauching,表示每次调试插件时是否提示清空运行时刻的Workspace。
可以选择“是”,表示重建运行时刻的Workspace。
插件打包
这一步是把用户开发的插件打包,供别人使用。
具体步骤如下。
(1)选择“Hello,world”插件,单击鼠标右键,选择“Export”菜单,弹出图6所示的对话框。
图6 插件打包对话框
(2)输入用户想要打包的文件名。
如果想把源文件也打包,可以选择“Include source code”复选框。
现在“Hello,world”插件就已经成功打包了。
(3)把“Hello,world”插件解压缩拷贝到用户的Eclipse的Plugins目录下面。
运行Eclipse,就可以在运行环境下看到“Hello,world”插件的身影了。
通过Export 菜单对插件进行打包,实际上Eclipse会读取插件目录下的
build.properties文件,通过它来描述需要打包的内容。
提示:不要把“Hello,World”插件拷贝到开发环境的Eclipse下面,否则插件可能不会被注册。
因为开发环境的Workspace中有相同ID的插件,这样会产生冲突。
要养成好习惯,把开发环境和部署环境分开。
插件描述文件
Eclipse中插件的描术文件包括Plugin.xml文件和MANIFEST.MF:
l Plugin.xml:Plugin.xml描述了扩展点的基本信息,包括扩展点的实现和定义,它按照扩展点的定义文件(schema)描述扩展的信息。
l MANIFEST.MF:MANIFEST.MF记录了插件的状态信息,包括插件的依赖关系、运行时的类加载路径以及插件的名称等。
Plugin.xml主要是通过XML文件格式描述扩展点的具体内容。
当Eclipse启动后,它将会找到所有插件的描述文件。
当Eclipse第一次启动某一个插件时,它会从MANIFEST.MF文件读取插件的相关信息,并通过定义的插件类初始化插件。
插件描述文件编辑器窗口,如图7所示。
图7 清单文件编辑窗口
Manifest.MF文件中保存了插件的基本信息(和OSGI相关的信息),而Plugin.xml文件记录了扩展点的信息,这两个文件在一个编辑器中展现,分成如下几个部分。
l Overview:描述了插件的基本信息。
l Dependencies:描述了插件的依赖关系。
l Runtime:指明运行时的ClassPath。
l Extensions:指明插件实现的扩展点。
l Extension Points:指明插件提供的扩展点。
1. OverView:描述了插件的基本信息
OverView描述了插件的基本信息,如图8所示。
图8 OverView页面
l ID:ID是插件的ID号,在Eclipse中是一个具体标识。
l Version:Version指明用户所开发的插件的版本号。
l Name:指用户所开发的插件的名称。
l Provider:开发者。
l Class:Class是指插件类,它由Eclipse建立并初始化,后面的章节将会详细介绍。
l Platform. Filter:指定平台相关的一些信息,一般来说用户不需要设定。
提示:ID号在Eclipse中是一个全局的标识。
很多初学者常常会对不同的插件命名成相同的ID号,这样会导致插件不能加载。
2. Dependencies:描述了插件的依赖关系
Dependencies页面描述了插件的依赖关系,如图9所示,插件依赖org.eclipse.ui和org.eclipse.core.runtime插件。
图9 Dependencies页面
Dependencies是一个比较重要的概念。
每一个插件有独立的ClassPath,Dependencies 会把依赖的插件的ClassPath加入到当前的ClassPath中。
提示:插件可以调用依赖的插件中所有导出的类,但插件不能够有循环依赖,所以在设计插件的结构时一定要设计合理,切记、切记。
3. Runtime:指明了运行时的ClassPath
Runtime:指明了运行时的ClassPath。
如图10所示,jdom.jar为此插件运行时依赖的包。
图10 Runtime页面
在Exported packages中也加入了一些要导出的包,如果不导出这些包,其它依赖当前插件的插件就用不了当前插件中对应包下的类。
Runtime也是一个比较重要的概念,它指明了运行时的环境。
Eclipse中插件不会引用到系统的ClassPath,每一个插件都有独立的ClassPath。
提示:很多人在开发插件时,没有通过Runtime指明ClassPath,而是直接添加Jar包,这样,在编译期间可能不会出错,但是在插件运行时会提示类找不到(ClassNotFoundException),就是这个问题。
4. Extensions:指明插件实现的扩展点
Extensions:指明插件实现的扩展点。
例如插件要实现“org.eclipse.ui.actionSets”扩展点,如图11所示。
图11 Extensions页面
Extensions是用户在开发一个插件中用到的扩展点,也是Eclipse开发的精髓所在。
后面章节的主要工作就是围绕扩展点展开的。
下面为扩展点在Plugin.xml文件中定义的片段。
<!-- 实现的扩展点 -->
<extension
point="org.eclipse.ui.actionSets">
<actionSet
label="Sample Action Set"
visible="true"
id="com.test.helloworld.actionSet">
<menu
label="Sample &Menu"
id="sampleMenu">
<separator
name="sampleGroup">
</separator>
</menu>
<action
label="&Sample Action"
icon="icons/sample.gif"
<!-- 扩展点的实现类 -->
class="com.test.helloworld.actions.SampleAction"
tooltip="Hello, Eclipse world"
menubarPath="sampleMenu/sampleGroup"
toolbarPath="sampleGroup"
id="com.test.helloworld.actions.SampleAction">
</action>
</actionSet>
</extension>
5. Extension Points:指明了用户插件提供的扩展点
Extension Points:指明了用户插件提供的扩展点。
如图12所示,此处为UI插件所提供的扩展点。
图12 插件提供扩展点
Eclipse的强大功能就是提供插件的扩展机制,用户可以实现他人提供的扩展点,也可以通过“Extension Points”为他人提供扩展点。
提示:实现扩展点和提供的扩展点是两个不同的概念。
实现扩展点是利用其他插件提供的扩展点,实现用户想要完成的功能。
提供的扩展点是为其他插件提供扩展所需要的接口。
视图插件
视图是工作台页面内的可视组件,通常用来浏览信息的层次结构(如工作空间)、打开编辑器或显示活动编辑器的属性。
用户可以通过“Window”→“Show view”菜单显示视图,也可以从视图局部标题栏关闭视图。
视图分类
在Eclipse中用户可以在同一时间打开多个视图(编辑器在同一时间只能打开一个),每个视图能够有自己的位置布局信息,Eclipse会根据上一次视图布局的信息初始化视图。
Eclipse视图一般来说有两种表现形式,一种是用户通过视图扩展点
“org.eclipse.ui.views”实现自定义的视图,另一种是实现Eclipse中视图提供的扩展,用户可以通过实现Eclipse的相应接口实现,如Outline视图和Properties视图,如图1所示。
图1 Eclipse视图
在Eclipse中,用户可以按自己的要求建立自己的视图,即扩展Eclipse的视图扩展点。
也能实现Eclipse的接口,通过Eclipse的Adapter机制实现Eclipse的扩展。
其中,Outline和Properties视图也是通过这种方式实现的,在后面的章节会介绍Outline视图和Properties视图的实现。
当用户定义了自己的视图后能通过“Window”→“Show view”菜单打开自定义的视图。
如图2所示。
图2 选择视图
常用视图可实现的功能
Eclipse的视图就功能来说一般有两种形式,一种是功能性视图,例如Java的Default视图,default负责用树形目录组织Java的项目结构,并且能通过双击节点在编辑器中打开相应的资源。
另一种视图是辅助型的视图,例如Console负责控制台信息的显示。
不管是哪种类型的视图,它们的实现原理是一样的。
在Eclipse中视图可以实现的功能有如下一些。
●右键菜单:可以通过视图中的树、表弹出的菜单完成相应的功能。
●工具栏:可以定制视图的工具栏,完成当前视图的功能。
●表格:视图中可以加入表格以显示相应的表结构信息。
●树:视图中可以加入树结构以显示相应的树结构信息。
● Log 输出:视图中可以直接输出信息。
这些只是一般在Eclipse中可以看到的实现,用户可以把视图当做操作Eclipse接口。
提示:任何SWT的组件都可以作为视图的一部分,用户可以按自己的需求定制自己的视图。
创建“Tree viewer”视图
创建“Tree viewer”视图插件项目,步骤如下:
1. 打开新建向导。
单击Eclipse的“File”→“New”→“Other”菜单项,在弹出的对话框中选择Select对话框左边的 Plug-in Development 向导。
2. 建立一个空的插件项目。
●输入插件工程的名字为“com.free.view. treeview”。
●输入插件的ID为“com.free.view.treeview”。
●输入插件的Name为“helloworld Plug-in”。
●选择使用模板建立插件项目,如图3所示。
●单击“Next”按钮,选择“Tree viewer”选项。
●单击“Finish”按钮,完成项目的建立。
图3 选择插件模板对话框
通过这种方式建立了一个包含JFace的“Tree viewer”组件的插件项目,此项目已经具备了视图插件常用的功能。
视图扩展点
通过插件模板创建了“Tree viewer”视图插件,此插件只实现了一个视图分类节点和视图节点。
如例程1所示。
例程1 plugin.xml
<plugin>
<extension
point="org.eclipse.ui.views">
<category
name="tree view"
id="com.free.view.categoryall">
</category>
<view
name="Tree View"
icon="icons/tree.GIF"
category="com.free.view.categoryall"
class="com.free.view.treeview.views.TreeViewTest"
id="com.free.view.treeview.views.TreeViewTest">
</view>
</extension>
</plugin>
“plugin.xml”实现了视图的扩展点“org.eclipse.ui.views”,Eclipse会根据扩展点的信息展现视图。
视图扩展点的实现类
在“Tree viewer”视图中要完成的功能有:树、菜单、工具栏和事件响应事件。
“Tree viewer”视图的实现类为“TreeViewTest”,通过实现类能实现这些功能。
实现类中要完成如下的功能。
1. 初始化树。
2. 完成菜单和工具栏响应的Action。
3. 完成上下文菜单。
4. 完成工具栏。
5. 完成双击树节点的响应方式。
在createPartControl方法中能对视图进行初始化,代码片段如下。
public void createPartControl(Composite parent) {
//初始化树
viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); drillDownAdapter = new DrillDownAdapter(viewer);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setSorter(new NameSorter());
viewer.setInput(getViewSite());
//完成菜单和工具栏响应的Action
makeActions();
//完成上下文菜单
hookContextMenu();
//完成双击树节点的响应方式
hookDoubleClickAction();
//完成工具栏
contributeToActionBars();
}
通过实现类,用户能加入自己感兴趣的功能。
“Tree viewer”视图中实现类的完整代码如例程2所示。
例程2 TreeViewTest.java
public class TreeViewTest extends ViewPart {
private TreeViewer viewer;
private DrillDownAdapter drillDownAdapter;
private Action action1;
private Action action2;
private Action doubleClickAction;
//创建树节点
class TreeObject implements IAdaptable {
private String name;
private TreeParent parent;
public TreeObject(String name) {
= name;
}
public String getName() {
return name;
}
public void setParent(TreeParent parent) {
this.parent = parent;
}
public TreeParent getParent() {
return parent;
}
public String toString() {
return getName();
}
public Object getAdapter(Class key) {
return null;
}
}
class TreeParent extends TreeObject {
private ArrayList children;
public TreeParent(String name) {
super(name);
children = new ArrayList();
}
public void addChild(TreeObject child) {
children.add(child);
child.setParent(this);
}
public void removeChild(TreeObject child) {
children.remove(child);
child.setParent(null);
}
public TreeObject [] getChildren() {
return (TreeObject [])children.toArray(new TreeObject[children.size()]); }
public boolean hasChildren() {
return children.size()>0;
}
}
//实现内容提供器
class ViewContentProvider implements IStructuredContentProvider, ITreeContentProvider {
private TreeParent invisibleRoot;
public void inputChanged(Viewer v, Object oldInput, Object newInput) { }
public void dispose() {
}
public Object[] getElements(Object parent) {
if (parent.equals(getViewSite())) {
if (invisibleRoot==null) initialize();
return getChildren(invisibleRoot);
}
return getChildren(parent);
}
public Object getParent(Object child) {
if (child instanceof TreeObject) {
return ((TreeObject)child).getParent();
}
return null;
}
public Object [] getChildren(Object parent) { if (parent instanceof TreeParent) {
return ((TreeParent)parent).getChildren();
}
return new Object[0];
}
public boolean hasChildren(Object parent) {
if (parent instanceof TreeParent)
return ((TreeParent)parent).hasChildren(); return false;
}
//初始化树节点
private void initialize() {
TreeObject to1 = new TreeObject("Leaf 1"); TreeObject to2 = new TreeObject("Leaf 2"); TreeObject to3 = new TreeObject("Leaf 3"); TreeParent p1 = new TreeParent("Parent 1");
p1.addChild(to1);
p1.addChild(to2);
p1.addChild(to3);
TreeObject to4 = new TreeObject("Leaf 4"); TreeParent p2 = new TreeParent("Parent 2");
p2.addChild(to4);
TreeParent root = new TreeParent("Root"); root.addChild(p1);
root.addChild(p2);
invisibleRoot = new TreeParent(""); invisibleRoot.addChild(root);
}
}
//实现标签提供器
class ViewLabelProvider extends LabelProvider {
public String getText(Object obj) {
return obj.toString();
}
public Image getImage(Object obj) {
String imageKey = ISharedImages.IMG_OBJ_ELEMENT;
if (obj instanceof TreeParent)
imageKey = ISharedImages.IMG_OBJ_FOLDER;
return PlatformUI.getWorkbench().getSharedImages().getImage(imageKey);
}
}
class NameSorter extends ViewerSorter {
}
public TreeViewTest() {
}
public void createPartControl(Composite parent) {
viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL); drillDownAdapter = new DrillDownAdapter(viewer);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
viewer.setSorter(new NameSorter());
viewer.setInput(getViewSite());
makeActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
}
//提供右键菜单
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
TreeViewTest.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
//提供视图工具栏
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalPullDown(IMenuManager manager) {
manager.add(action1);
manager.add(new Separator());
manager.add(action2);
}
//填充菜单
private void fillContextMenu(IMenuManager manager) {
manager.add(action1);
manager.add(action2);
manager.add(new Separator());
drillDownAdapter.addNavigationActions(manager);
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(action1);
manager.add(action2);
manager.add(new Separator());
drillDownAdapter.addNavigationActions(manager);
}
//创建菜单和工具栏对应的Action
private void makeActions() {
action1 = new Action() {
public void run() {
showMessage("Action 1 executed");
}
};
action1.setText("Action 1");
action1.setToolTipText("Action 1 tooltip");
action1.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages(). getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));
action2 = new Action() {
public void run() {
showMessage("Action 2 executed");
}
};
action2.setText("Action 2");
action2.setToolTipText("Action 2 tooltip");
action2.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages(). getImageDescriptor(ISharedImages.IMG_OBJS_INFO_TSK));
doubleClickAction = new Action() {
public void run() {
ISelection selection = viewer.getSelection();
Object bj = ((IStructuredSelection)selection).getFirstElement(); showMessage("Double-click detected on "+obj.toString());
}
};
}
private void hookDoubleClickAction() {
viewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
doubleClickAction.run();
}
});
}
private void showMessage(String message) {
MessageDialog.openInformation(
viewer.getControl().getShell(),
"Tree View",
message);
}
//响应获得焦点
public void setFocus() {
viewer.getControl().setFocus();
}
}
上例中通过内容提供器(ViewContentProvider)、标签提供器(ViewLabelProvider)及树节点(TreeObject)的定义提供了树的实现,另外通过createPartControl方法实现了相应的菜单和工具栏。
提示:本例中右键菜单和工具栏的实现方式非常值得效仿,而且非常直观,读者可以比较一下在SWT中的实现方式,找到它们之间的异同点。
运行“Tree viewer”视图
“Tree viewer”插件到此就已经完成,现在可以调试插件了。
1. 运行插件。
2. 打开运行时工作台的“Show View”。
在“Show View”窗口中可以看到前面建立的分类和视图节点。
3. 运行“Tree viewer”视图
双击“Tree View”节点,打开视图窗口,如图4所示。
图4 “Tree viewer”视图
在Eclipse插件的开发中,视图插件的开发是比较重要的一个部分。
视图是工作台页面内的可视组件,用户可以通过视图,扩展Eclipse原有的功能。
插件开发时常用的组件
在SWT的开发过程中,用户会经常使用到打印对话框、颜色对话框、字体对话框、文件对话框和目录对话框等对话框等,在些将简单介绍这些对话框的使用。
颜色对话框(ColorDialog)
当用户要改变颜色的设置,就要用到颜色对话框,如图1所示。
图1 颜色对话框
用户可以通过如下代码片段新建颜色对话框,并设置标签的颜色。
//新建颜色对话框
ColorDialog dlg = new ColorDialog(shell);
//设置默认的颜色
dlg.setRGB(colorLabel.getBackground().getRGB());
//设置标题字体
dlg.setText("Choose a Color");
//打开对话框
RGB rgb = dlg.open();
if (rgb != null) {
color.dispose();
color = new Color(shell.getDisplay(), rgb);
//设置标签的颜色
colorLabel.setBackground(color);
}
字体对话框(FontDialog)
用户可以通过字体对话框选择字体及字体的颜色,如图2所示。
图2 字体对话框
新建字体对话框比较简单,如下代码片段演示如何设置字体对话框的初始字体和颜色,以及选择了相应的字体和颜色后设置标签的字体和颜色。
// 新建字体对话框
FontDialog dlg = new FontDialog(shell);
//设置初始字体和颜色
if (font != null) dlg.setFontList(fontLabel.getFont().getFontData());
if (color != null) dlg.setRGB(color.getRGB());
//打开对话框
if (dlg.open() != null) {
if (font != null) font.dispose();
if (color != null) color.dispose();
//新建字体对象
font = new Font(shell.getDisplay(), dlg.getFontList());
//设置标签的字体
fontLabel.setFont(font);
//新建颜色对象
color = new Color(shell.getDisplay(), dlg.getRGB());
//设置标签颜色
fontLabel.setForeground(color);
文件对话框(FileDialog)
文件对话框是比较常用的对话框,当用户要从磁盘选择文件时将用文件对话框选取文件,如图3所示。
图3 文件对话框
新建文件对话框,用户可以设置对话框的初始路径、标题和扩展名过滤等属性,如下代码片段所示。
//新建文件对话框,并设置为打开的方式
FileDialog fd = new FileDialog(s, SWT.OPEN);
//设置文件对话框的标题
fd.setText("Open");
//设置初始路径
fd.setFilterPath("C:/");
//设置扩展名过滤
String[] filterExt = { "*.txt", "*.doc", ".rtf", "*.*" };
fd.setFilterExtensions(filterExt);
//打开文件对话框,返回选择的文件
String selected = fd.open();
System.out.println(selected);
目录对话框(DirectoryDialog)
目录对话框和文件对话框类似,用户可以通过目录对话框选择相应的目录,如图4所示。
图4 目录对话框
新建目录对话框,用户可以设置对话框的初始路径、标题和提示信息等属性,最后返回选择的目录,如下代码片段所示。
//新建目录对话框
DirectoryDialog dlg = new DirectoryDialog(shell);
//设置初始路径
dlg.setFilterPath(text.getText());
//设置对话框标题
dlg.setText("SWT's DirectoryDialog");
//设置提示信息
dlg.setMessage("Select a directory");
//打开对话框,返回目录
String dir = dlg.open();
if (dir != null) {
// Set the text box to the new selection
text.setText(dir);
}
打印对话框(PrintDialog)
打印对话框中用户能选择打印机和设置打印的一些选项,如图5所示。
新建打印对话框通过PrintDialog,例如“PrintDialog printDialog = new PrintDialog(s, SWT.NONE);”,另外,要打印相关的数据可以通过Printer对象。
图5 打印对话框
对话框是GUI程序开发中经常用到的组件。
在此介绍了常用的一些系统对话框,读者应该对对话框的功能和使用场景有所了解。
Tableviewer
这个是因为我要用的.所以自我感觉就重要.其它对于一般人重要与否这个没准.
一、构造一个树形结构的数据出来,这里选择国家、城市、人来构造一个树形结构,代码如下:
1,定义一个接口
package model;
import java.util.List;
public interface Itree {
public String getName();
public void setName(String name);
public void setChildren(List Children); public List getChildren();
}
2,国家
package model;
import java.util.ArrayList;
import java.util.List;
public class Country implements Itree{
private Long id;
private String name;
private List children = new ArrayList(); public Country(){
}
public Country(String name){
= name;
}
public List getChildren() {
return children;
}
public void setChildren(List children) { this.children = children;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
}
3,城市
package model;
import java.util.ArrayList;
import java.util.List;
public class City implements Itree{
private Long id;
private String name;
private List children = new ArrayList(); public City(){
}
public City(String name){
= name;
}
public List getChildren() {
return children;
}
public void setChildren(List children) { this.children = children;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
}
4,人
package model;
import java.util.ArrayList;
import java.util.List;
public class People implements Itree{
private Long id;
private String name;
public People(){
}
public People(String name){
= name;
}
public List getChildren() {
return null;
}
public void setChildren(List children) { }
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
= name;
}
}
5,把这些元素组织起来
package model;
import java.util.ArrayList;
import java.util.List;
public class Factory {
@SuppressWarnings("unchecked")
public static List createTree(){
//生成国家
Country cn = new Country("中国");
Country us = new Country("美国");
Country jp = new Country("日本");
//生成城市
City beijing = new City("北京");
City shanghai = new City("上海");
City newyork = new City("纽约");
City la = new City("洛杉矶");
City tokyo = new City("东京");
City osaka = new City("大阪");
//北京人
ArrayList list = new ArrayList(); list.add(new People("张三"));
list.add(new People("李四"));
list.add(new People("王五"));
beijing.setChildren(list);
//上海人
list = new ArrayList();
list.add(new People("翠花"));
list.add(new People("小红"));
list.add(new People("小崔"));
shanghai.setChildren(list);
//纽约人
list = new ArrayList();
list.add(new People("tom"));
list.add(new People("rose"));
list.add(new People("john"));
newyork.setChildren(list);
//洛杉矶人
list = new ArrayList();
list.add(new People("Sofia"));
list.add(new People("sarah"));
list.add(new People("Jennifer")); la.setChildren(list);
//东京人
list = new ArrayList();
list.add(new People("渡边"));
list.add(new People("鬼冢"));
list.add(new People("山本"));
tokyo.setChildren(list);
//大阪人
list = new ArrayList();
list.add(new People("奈奈子"));
list.add(new People("菜菜子"));
list.add(new People("新垣结衣")); osaka.setChildren(list);
//关联城市与国家
//中国
ArrayList citys = new ArrayList(); citys.add(beijing);
citys.add(shanghai);
cn.setChildren(citys);
//美国
citys = new ArrayList();
citys.add(newyork);
citys.add(la);
us.setChildren(citys);
//日本
citys = new ArrayList();
citys.add(tokyo);
citys.add(osaka);
jp.setChildren(citys);
//国家列表
ArrayList countrys = new ArrayList();
countrys.add(cn);
countrys.add(us);
countrys.add(jp);
return countrys;
}
}
二、定义内容器和标签器
1,内容器
import java.util.List;
import model.Itree;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
public class TreeContentProvider implements IStructuredContentProvider, ITreeContentProvider {
public Object[] getElements(Object inputElement) {
if (inputElement instanceof List){
List input = (List)inputElement;
return input.toArray();
}
return new Object[0];
}
public Object[] getChildren(Object parentElement) {
Itree node = (Itree)parentElement;
List list = node.getChildren();
if(list == null){
return new Object[0];
}
return list.toArray();
}
public boolean hasChildren(Object element) {
Itree node = (Itree)element;
List list = node.getChildren();
return !(list == null || list.isEmpty());
}
//以下三个函数根据需要填充
public Object getParent(Object element) {
return null;
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public void dispose() {
}
}
2,标签器:
import model.Itree;
import org.eclipse.jface.viewers.ILabelProvider;
import belProvider;
import org.eclipse.swt.graphics.Image;
public class TreeLabelProvider extends LabelProvider implements ILabelProvider {
public String getText(Object element) {
Itree node = (Itree)element;
return node.getName();
}
public Image getImage(Object element) {
return null;
}
}
三、好了,准备工作做好了,把上边的内容利用起来就好了。
import model.Factory;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import yout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
public class TestTreeViewer {
private static Tree tree;
public static void main(String[] args) {
final Display display = Display.getDefault();
final Shell shell = new Shell();
shell.setSize(500, 375);
shell.setText("SWT Application");
//
final TreeViewer treeViewer = new TreeViewer(shell,
SWT.BORDER|SWT.H_SCROLL);
tree = treeViewer.getTree();
tree.setBounds(83, 75, 264, 185);
treeViewer.setLabelProvider(new TreeLabelProvider());
treeViewer.setContentProvider(new TreeContentProvider());
treeViewer.setInput(Factory.createTree());
shell.open();
shell.setLayout(new FillLayout());
yout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
}
}
看看是不是已经实现了treeViewer
四、上边是简单的treeViewer,如果我们需要带checkbox的treeViewer,简单,只需要更改
final TreeViewer treeViewer = new TreeViewer(shell, SWT.BORDER|SWT.H_SCROLL);
把TreeViewer换成CheckboxTreeViewer。
这就是mvc的好处了。
但现实中我们多用ContainerCheckedTreeViewer代替CheckboxTreeViewer,因为这个提供了更多的功能。
CheckboxTreeViewer是TreeViewer的子类, ContainerCheckedTreeViewer是CheckboxTreeViewer的子类,所以可以随便替换。
替换后:
final ContainerCheckedTreeViewer treeViewer = new ContainerCheckedTreeViewer(shell, SWT.BORDER|SWT.H_SCROLL);
五、treeviewer和tableviewer都介绍过了,考虑一下把两个结合起来是不是我们经常需要的情况。
尝试一下吧。
TitleAreaDialog 实现
Dialog是SWT和JFace的一个重要的组成部分,我们在开发Plug-in或RCP的时候也经常会用到它们。
这篇随笔不会介绍SWT的Dialog,因为我想很多人都已经非常熟悉它了。
在这里,我要讨论的是JFace的Dialog,或者更进一步说是JFace的TitleAreaDialog。
什么是TitleAreaDialog呢?想想我们常常用到的New XX Wizard就知道了。
在我们创建一个Java Project或Class的时候,我们所使用的Wizard其实就是由TitleAreaDialog构成的。
这种GUI的表现力要比SWT的Dialog强很多,而且JFace为该Dialog封装了很多东西,这也使开发工作变得更加简单,所以我极力推荐使用TitleAreaDialog。
那么让我们来看一个最基本的TitleAreaDialog:
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import yout.GridData;
import posite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.jthin.jpssp.ide.configuration.Activator;
public class MyTitleAreaDialog extends TitleAreaDialog {
/**
* Create the dialog
*
* @param parentShell
*/
public MyTitleAreaDialog(Shell parentShell) {
super(parentShell);
}
/*
* (non-Javadoc)
*
* @see
org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(posit e)
*/
protected Control createDialogArea(Composite parent) {
Composite area = (Composite) super.createDialogArea(parent);
Composite container = new Composite(area, SWT.NONE);
container.setLayoutData(new GridData(GridData.FILL_BOTH));
// TitleArea中的Title
setTitle("My TitleAreaDialog");
// TitleArea中的Message
setMessage("This is a simple TitleAreaDialog example.");
// TitleArea中的Image
setTitleImage(ResourceManager.getPluginImage(Activator.getDefault(),
"icons/Neptune.png"));
return area;
}
/*
* (non-Javadoc)
*
* @see
org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(posi te)
*/
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.TitleAreaDialog#getInitialSize()
*/
protected Point getInitialSize() {
return new Point(500, 375);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) */
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
// Dialog Title
newShell.setText("Test TitleAreaDialog Title");
// Dialog Icon
newShell.setImage(ResourceManager.getPluginImage(Activator.getDefault(),
"icons/Neptune.png"));
}
}
这段代码非常容易理解,从方法签名中可以看出每个方法做了什么事情。
注意createButtonsForButtonBar方法,其中用createButton方法创建了OK和Cancel这两个Button,并且把Button的默认点击事件也写好了,就是关闭该Dialog。
ResourceManager.getPluginImage是我自己编写的获得图片的helper method,这里就不讨论其实现了。
有趣的是,我在这里故意使用了一个128×128的大图标,TitleAreaDialog不会自动缩小或裁减Image,而是调整TitleArea的大小来适应Image。
接下来我们要为OK Button编写我们自己的事件,例如把用户在Dialog中的输入保存到某处。
有人可能会想到为OK Button添加SelectionListener,但实际上这样做是不对的,因为OK Button 是JFace为Dialog封装好了的,同时JFace也提供了响应的callback:
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.dialogs.Dialog#okPressed()
*/
protected void okPressed() {
// implement your own function here
super.okPressed();
}
我们可以在这里实现我们自己的事件,不过最后一定要调用super.okPressed方法,否则Dialog 就不会关闭了。
OK,以上就是TitleAreaDialog的基本Framework,非常容易理解,下面我们就来在TitleArea 中动态设置一些信息。
你可以把这个scenario想象成在用户输入的同时提示用户输入的合法性。
TitleAreaDialog提供了好3个方法可以动态设置TitleArea信息,具体如下:。