<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!--
//作者:陈小朋 2007-01-07
window.Menu=function(isDir,text,handle)
{
this.HTMLObj=null; //关联HTML对象
this.ParentMenu=null; //父菜单
this.SubMenus=[]; //存储子菜单数组
this.ZIndex=900; //层
this.IsDirectory=isDir?isDir:false; //是否是目录
this.Text=text?text:"";
this.Handle=handle?handle:""; //单击时所执行的语句,目录不支持此属性
//创建并追加子菜单
this.CreateSubMenu=function(isDir,text,handle)
{
if(this.IsDirectory)
{
var oMenu=new Menu();
if(typeof(isDir)!="undefined")
{
oMenu.IsDirectory=isDir;
}
if(typeof(text)!="undefined")
{
oMenu.Text=text;
}
if(typeof(handle)!="undefined")
{
oMenu.Handle=handle;
}
this.AppendSubMenu(oMenu);
return oMenu;
}
alert("出现错误,该对象不支持CreateSubMenu方法");
return null;
}
//追加子菜单
this.AppendSubMenu=function(oMenu)
{
this.SubMenus.push(oMenu);
oMenu.ParentMenu=this;
oMenu.ZIndex=this.ZIndex+1;
}
//插入子菜单
this.InsertSubMenu=function(oMenu,iAlign)
{
if(iAlign>=this.SubMenus.length)
{
this.SubMenus.push(oMenu);
}
else
{
this.SubMenus.splice(iAlign,0,oMenu);
}
oMenu.ParentMenu=this;
oMenu.ZIndex=this.ZIndex+1;
}
//移除子菜单
this.RemoveSubMenu=function(iAlign)
{
var RemoveArr=this.SubMenus.splice(iAlign,1);
if(RemoveArr.length>0)
{
if(RemoveArr[0].IsDirectory)
{
RemoveArr[0].Clear();
}
else
{
RemoveArr[0].HTMLObj.parentNode.removeChild(RemoveArr[0].HTMLObj);
}
}
}
//把子菜单的数据转换成HTML格式
this.Create=function()
{
if(!this.IsDirectory)
{
alert("出现错误,该对象不支持Create方法");
return false;
}
var ParentElement=document.createElement("span");
this.ChildMenuHTMLObj=ParentElement; //关联子菜单的HTML对象容器
ParentElement.style.cursor="default";
ParentElement.style.position="absolute";
ParentElement.style.visibility="hidden";
ParentElement.style.zIndex=this.ZIndex;
ParentElement.style.border="1px solid #464646";
ParentElement.style.borderRight="1px solid #aaa";
ParentElement.style.borderBottom="1px solid #aaa";
ParentElement.style.borderTop="1px solid #fff";
ParentElement.style.borderLeft="1px solid #fff";
ParentElement.οnmοusedοwn=function(e)
{
Menu.Config.IsIE?window.event.cancelBubble=true:e.stopPropagation();
}
ParentElement.onselectstart=function()
{
return false;
}
var table=document.createElement("table");
table.cellPadding=0;
table.cellSpacing=0;
var tbody=document.createElement("tbody");
var tr=document.createElement("tr");
var ltd=document.createElement("td");
var rtd=document.createElement("td");
ltd.style.width="25px";
ltd.style.backgroundImage="url(http://www.fjcjhr.com/bg.gif)";
ltd.innerHTML=Menu.Config.IsIE?"<pre> </pre>":"<pre> </pre>";
tr.appendChild(ltd);
tr.appendChild(rtd);
tbody.appendChild(tr);
table.appendChild(tbody);
ParentElement.appendChild(table);
var len=this.SubMenus.length;
if(len>0)
{
var ChildTable=document.createElement("table");
var ChildTBody=document.createElement("tbody");
ChildTable.border=0;
ChildTable.cellPadding=0;
ChildTable.cellSpacing=0;
ChildTable.style.fontSize=Menu.Config.FontSize;
ChildTable.style.color=Menu.Config.FontColor;
ChildTable.appendChild(ChildTBody);
rtd.appendChild(ChildTable);
}
for(var i=0;i<len;i++)
{
var tempTr=document.createElement("tr");
//关联HTML对象和DATA对象
this.SubMenus[i].HTMLObj=tempTr; //关联子菜单的HTML对象
tempTr.DataObj=this.SubMenus[i];
var tempTd=document.createElement("td");
tempTr.style.backgroundColor=Menu.Config.BgColor;
tempTr.appendChild(tempTd);
tempTd.style.height=Menu.Config.PerMenuHeight;
tempTd.vAlign="middle";
tempTd.style.paddingLeft="5px";
tempTd.style.paddingRight="5px";
tempTr.οnmοuseοver=this.SubMenus[i].MouseOver;
tempTr.οnmοuseοut=this.SubMenus[i].MouseOut;
tempTr.οnclick=this.SubMenus[i].Click;
tempTd.innerHTML="<nobr>"+this.SubMenus[i].Text+"</nobr>";
var DirectoryTd=document.createElement("td");
if(this.SubMenus[i].IsDirectory)
{
DirectoryTd.innerHTML="<font face='webdings'>4</font>";
}
tempTr.appendChild(DirectoryTd);
ChildTBody.appendChild(tempTr);
}
document.body.appendChild(ParentElement);
for(var i=0;i<len;i++)
{
if(this.SubMenus[i].IsDirectory)
{
this.SubMenus[i].Create();
}
}
}
this.Show=function(e)
{
if(!this.IsDirectory)
{
alert("出现错误,该对象不支持Show方法");
return false;
}
if(this.SubMenus.length==0) return;
var ChildHTMLObj=this.ChildMenuHTMLObj;
var DWidth=document.body.clientWidth;
var DHeight=document.body.clientHeight;
var left=document.body.scrollLeft,top=document.body.scrollTop;
var x,y;
if(this.ParentMenu==null) //根对象
{
x=e.clientX,y=e.clientY;
if(x+ChildHTMLObj.offsetWidth>DWidth)
{
x-=ChildHTMLObj.offsetWidth;
}
if(y+ChildHTMLObj.offsetHeight>DHeight)
{
y-=ChildHTMLObj.offsetHeight;
}
x+=left;
y+=top;
}
else
{
var CurrentHTMLObj=this.HTMLObj;
var x=Menu.GetMenuPositionX(CurrentHTMLObj)+CurrentHTMLObj.offsetWidth,y=Menu.GetMenuPositionY(CurrentHTMLObj);
if(x+ChildHTMLObj.offsetWidth>DWidth+left)
{
x-=(CurrentHTMLObj.offsetWidth+ChildHTMLObj.offsetWidth);
}
if(y+ChildHTMLObj.offsetHeight>DHeight+top)
{
y-=ChildHTMLObj.offsetHeight;
y+=CurrentHTMLObj.offsetHeight;
}
}
ChildHTMLObj.style.left=x;
ChildHTMLObj.style.top=y;
this.ChildMenuHTMLObj.style.visibility="visible";
}
this.Hidden=function()
{
if(!this.IsDirectory)
{
alert("出现错误,该对象不支持Hidden方法");
return false;
}
var len=this.SubMenus.length;
for(var i=0;i<len;i++)
{
if(this.SubMenus[i].IsDirectory)
{
this.SubMenus[i].Hidden();
}
}
this.ChildMenuHTMLObj.style.visibility="hidden";
}
this.MouseOver=function(e)
{
this.style.backgroundColor=Menu.Config.OverBgColor;
var ParentMenu=this.DataObj.ParentMenu;
var len=ParentMenu.SubMenus.length;
for(var i=0;i<len;i++)
{
if(ParentMenu.SubMenus[i].IsDirectory)
{
ParentMenu.SubMenus[i].Hidden();
}
}
if(this.DataObj.IsDirectory)
{
e=e?e:event;
this.DataObj.Show(e);
}
}
this.MouseOut=function()
{
this.style.backgroundColor=Menu.Config.BgColor;
}
this.Clear=function()
{
if(this.IsDirectory)
{
var len=this.SubMenus.length;
for(var i=0;i<len;i++)
{
if(this.SubMenus[i].IsDirectory)
{
this.SubMenus[i].Clear();
}
}
}
document.body.removeChild(this.ChildMenuHTMLObj);
}
this.Click=function()
{
if(!this.DataObj.IsDirectory)
{
eval_r(this.DataObj.Handle);
Menu.Config.FirstMenu.Hidden();
}
}
}
//菜单配置
Menu.Config=
{
FirstMenu:new Menu(true), //系统定义的第一个菜单,必须为容器(IsDirectory=true)
BgColor:"#FFFFFF", //设置菜单背景颜色
OverBgColor:"#B5BED6", //设置菜单鼠标经过时的背景颜色
FontSize:"13px", //设置菜单字体大小
FontColor:"#000000", //设置菜单字体颜色
PerMenuHeight:"25px", //调整菜单的行距
IsIE:document.all?true:false
};
Menu.GetMenuPositionX=function(obj)
{
var ParentObj=obj;
var left;
left=ParentObj.offsetLeft;
while(ParentObj=ParentObj.offsetParent){
left+=ParentObj.offsetLeft;
}
return left;
}
Menu.GetMenuPositionY=function(obj)
{
var ParentObj=obj;
var top;
top=ParentObj.offsetTop;
while(ParentObj=ParentObj.offsetParent){
top+=ParentObj.offsetTop;
}
return top;
}
Menu.Update=function()
{
var FirstMenu=Menu.Config.FirstMenu;
FirstMenu.Clear();
FirstMenu.Create();
}
//事件
window.οnlοad=function()
{
Menu.Config.FirstMenu.Create();
document.οncοntextmenu=function(e)
{
Menu.Config.FirstMenu.Hidden();
e=e?e:event;
Menu.Config.FirstMenu.Show(e);
return false;
}
document.οnmοusedοwn=function()
{
Menu.Config.FirstMenu.Hidden();
}
}
//*************************************系统实例******************************************
window.CXP_Menu=Menu.Config.FirstMenu;
var pg=CXP_Menu.CreateSubMenu();
pg.Text="程序(P)";
pg.IsDirectory=true;
var wd=new Menu(true,"文档(D)");
CXP_Menu.AppendSubMenu(wd);
var set=CXP_Menu.CreateSubMenu(true,"设置(S)");
var help=CXP_Menu.CreateSubMenu(false,"帮助(H)");
help.Handle="alert('这是帮助!')";
var run=CXP_Menu.CreateSubMenu(false,"运行(R) ...","alert('这是运行!')");
var exit=new Menu();
exit.Text="关机(U) ...";
CXP_Menu.AppendSubMenu(exit);
//插入菜单
CXP_Menu.InsertSubMenu(new Menu(false,"Windows Update","if(confirm('此处通向MS官方,您真的要去吗?'))location.href='http://windowsupdate.microsoft.com/'"));
pg.AppendSubMenu(new Menu(false,"程序1 ..."));
pg.AppendSubMenu(new Menu(false,"程序2"));
pg.AppendSubMenu(new Menu(false,"程序4"));
pg.AppendSubMenu(new Menu(false,"程序5"));
pg.AppendSubMenu(new Menu(false,"程序6"));
wd.AppendSubMenu(new Menu(false,"文档1 ..."));
wd.AppendSubMenu(new Menu(false,"文档2"));
set.AppendSubMenu(new Menu(false,"设置1 ..."));
set.AppendSubMenu(new Menu(false,"设置2"));
var pg3=new Menu(true,"程序3");
pg3.AppendSubMenu(new Menu(false,"程序4"));
pg3.AppendSubMenu(new Menu(false,"程序5"));
pg3.AppendSubMenu(new Menu(false,"程序6 ......."));
pg.AppendSubMenu(pg3);
function change()
{
exit.Text="关鸡!";
Menu.Update();
}
function add()
{
CXP_Menu.AppendSubMenu(new Menu(false,"我是新加的!"));
Menu.Update();
}
function del()
{
CXP_Menu.RemoveSubMenu(0);
}
//-->
</SCRIPT>
</HEAD>
<BODY bgcolor=#000000 leftmargin=0 topmargin=0 style="color:#FFFFFF">
<input type="button" value="添加新菜单" οnclick="add()">
<input type="button" value="把关机修改成关鸡^_^" οnclick="change()">
<input type="button" value="删除顶菜单" οnclick="del()">
</BODY>
</HTML>
1.extends是继承父类,只要那个类不是声明为final或者那个类定义为abstract的就能继承,JAVA中不支持多重继承,但是可以用接口来实现,这样就要用到implements,继承只能继承一个类,但implements可以实现多个接口,用逗号分开就行了,
比如 :class A extends B implements C,D,E;
2.extends 是继承某个类
继承之后可以使用父类的方法
也可以重写父类的方法
implements 是实现多个接口
接口的方法一般为空的
必须重写才能使用
Eclipse插件开发——添加菜单,工具条
Eclipse简介和插件开发: http://www.ibm.com/developerworks/cn/java/l-eclipse-plugin/ 添加菜单(menubar)项与添加工具条(toolbar)按钮的过程几乎相同。首先声明一个扩展(相同的扩展org.eclipse.ui.actionSets)、用特定的标记(相同或不同的标记都可以)来扩充它,并编写操作类(相同的类)。特定的标记是指添加菜单项或工具条的位置,建议让工具条和菜单条ID标志位置保持一致性。
下面是菜单项的扩展XML代码(没有相应的工具条按钮): <extension point="org.eclipse.ui.actionSets"> <actionSet label="Sample Action Set" visible="true" id="cn.guoyibj.sample.extendmenu.actionSet"> <action label="&Sample Action" icon="icons/sample.gif" class="cn.guoyibj.sample.extendmenu.actions.SampleAction" tooltip="Hello, Eclipse world" menubarPath="file/new.ext" id="cn.guoyibj.sample.extendmenu.actions.SampleAction"> </action> </actionSet> </extension> 代码1 运行效果如下图所示:   图1
下面是一个组合了菜单项和工具条按钮的例子: <extension point="org.eclipse.ui.actionSets"> <actionSet label="Sample Action Set" visible="true" id="cn.guoyibj.sample.extendmenu.actionSet"> <action label="&Sample Action" icon="icons/sample.gif" class="cn.guoyibj.sample.extendmenu.actions.SampleAction" tooltip="Hello, Eclipse world" menubarPath="file/new.ext" toolbarPath="org.eclipse.ui.workbench.file/new.ext" id="cn.guoyibj.sample.extendmenu.actions.SampleAction"> </action> </actionSet> </extension> 代码2 我们可以看到代码2比代码1只多了一行,我用粗体标识出来了。运行效果除了添加了图1中的菜单,还添加了如下图所示的工具条按钮:   图2
上面例子中的菜单和工具条的操作类继承IWorkbenchWindowActionDelegate,如果要实现分层工具条,操作类需要实现IWorkbenchWindowPulldownDelegate2接口。
下面是一个带子菜单和分层工具条的例子:
<extension point="org.eclipse.ui.actionSets"> <actionSet label="Copy File Action" visible="true" id="com.ibm.designer.extensibility.copyfile.actionSet"> <menu label="Copy File" id="copyFileMenu"> <separator name="copyFileGroup"> </separator> </menu> <action label="My Import Action" icon="icons/import.gif" class="cn.guoyibj.sample.extendmenu.actions.SubClassA" tooltip="My Import..." menubarPath="copyFileMenu/copyFileGroup" toolbarPath="copyFileGroup" id="cn.guoyibj.sample.extendmenu.actions.SubClassA"> </action> <action label="My Export Action" icon="icons/export.gif" class="cn.guoyibj.sample.extendmenu.actions.SubClassB" tooltip="My Export..." menubarPath="copyFileMenu/copyFileGroup" toolbarPath="copyFileGroup" retarget="false" style="pulldown" id="cn.guoyibj.sample.extendmenu.actions.SubClassB"> </action> </actionSet> </extension> 代码3
运行效果图如下: 
图3
  图4 我们修改一下菜单条的位置: <extension point="org.eclipse.ui.actionSets"> <actionSet label="Copy File Action" visible="true" id="com.ibm.designer.extensibility.copyfile.actionSet"> <action label="My Import Action" icon="icons/import.gif" class="cn.guoyibj.sample.extendmenu.actions.SubClassA" tooltip="My Import..." menubarPath="file/import.ext" id="cn.guoyibj.sample.extendmenu.actions.SubClassA"> </action> <action label="My Export Action" icon="icons/export.gif" class="cn.guoyibj.sample.extendmenu.actions.SubClassB" tooltip="My Export..." menubarPath="file/import.ext" retarget="false" style="pulldown" id="cn.guoyibj.sample.extendmenu.actions.SubClassB"> </action> </actionSet> </extension> 代码4 效果图如下所示: 
图5
[ 本帖最后由 guoyibj 于 2009-10-16 22:45 编辑 ]
|
只看该作者  |
guoyibj
精华贴数 0
个人空间 0
技术积分 120 (17457)
社区积分 0 (2018937)
注册日期 2008-12-22
论坛徽章:0
|
|
| |
菜单条路径(menubar path)指出了添加菜单项的位置,下面是经常使用的菜单条路径的列表。
文件:file
o "开始" 区:fileStart
o "新建"菜单内部的"附加"组标志: new/additions
o "新建"区,在"新建"菜单下面:new.ext
o "关闭" 区:close.ext
o "保存" 区:save.ext
o "打印" 区:print.ext
o "打开" 区:open.ext
o "导入" 区:import.ext
o "附加" 区:additions
o "最近的文档" 区:mru
o "结束" 区:fileEnd
编辑:edit
o "开始" 区:editStart
o "撤销" 区:undo.ext
o "剪切" 区:cut.ext
o "查找" 区:find.ext
o "添加" 区:add.ext
o "结束" 区(有时不是结束):fileEnd
o "附加" 区:additions
源:org.eclipse.jdt.ui.source.menu
重构:org.eclipse.jdt.ui.refactoring.menu
导航:navigate
o "开始"区:navStart
o "Go To"菜单中的"附加"组标志: goTo/additions
o "打开"区(有四个):open.ext, open.ext2, open.ext3, and open.ext4
o "显示"区(有四个):show.ext, show.ext2, show.ext3, and show.ext4
o "附加"区:additions
o "结束"区:navEnd
搜索:org.eclipse.search.menu
项目: project
o "开始"区:projStart
o "打开"区:open.ext
o "建立"区:build.ext
o "附加"区:additions
o "结束"区:projEnd
载入:launch
运行:org.eclipse.ui.run "附加"组标志:additions 窗口:window
o "附加"区:additions
o "结束"区:additionsend
帮助:help
o "开始"区:helpStart
o "主要组"区:group.main.ext
o "教程组"区:group.tutorials
o "工具组"区:group.tools
o "更新组"区:group.updates
o "结束"区(有时候不是结束): helpEnd
o "附加"区:additions
o "关于组"区:group.about.ext
| 只看该作者  | |
guoyibj
精华贴数 0
个人空间 0
技术积分 120 (17457)
社区积分 0 (2018937)
注册日期 2008-12-22
论坛徽章:0
|
|
| |
工具条路径(toolbar path)指出了添加工具条的位置。
下面是常用的工具条路径列表:
文件:org.eclipse.ui.workbench.file 带有一些公共的分组标志(你可以添加按钮的更多的位置):
o "新建"区:new.ext
o "保存"区:save.ext
o "打印"区:print.ext
o "建立"区:build.ext
导航:org.eclipse.ui.workbench.navigate
载入:org.eclipse.debug.ui.launchActionSet
编辑器表示:org.eclipse.ui.edit.text.actionSet.presentation
搜索:org.eclipse.search.searchActionSet
Java元素建立:org.eclipse.jdt.ui.JavaElementCreationActionSet
组:Team
CVS:CVS
[
本帖最后由 guoyibj 于 2009-10-16 00:23 编辑 ]
| 只看该作者  | |
guoyibj
精华贴数 0
个人空间 0
技术积分 120 (17457)
社区积分 0 (2018937)
注册日期 2008-12-22
论坛徽章:0
|
|
| |
右键弹出菜单(popup menu)
添加菜单项到右键弹出菜单,需要扩展org.eclipse.ui.popupMenus,并实现一个继承IObjectActionDelegate的类。
下面是一个右键弹出菜单的扩展XML的例子:
<extension point="org.eclipse.ui.popupMenus"> <objectContribution objectClass="org.eclipse.core.resources.IFile" adaptable="true" id="cn.guoyibj.sample.extendmenu.popupMenu"> <action label="New Action1" icon="icons/sample.gif" class="cn.guoyibj.sample.extendmenu.actions.PopupMenuAction" menubarPath="additions" enablesFor="1" id="test.newAction1"> </action> <menu label="New Submenu" path="additions" id="test.menu1"> <separator name="group1"> </separator> </menu> <action label="New Action2" icon="icons/sample.gif" class="cn.guoyibj.sample.extendmenu.actions.PopupMenuAction" menubarPath="test.menu1/group1" enablesFor="*" id="test.newAction2"> </action> <action label="New Action3" icon="icons/sample.gif" class="cn.guoyibj.sample.extendmenu.actions.PopupMenuAction" menubarPath="abc" enablesFor="*" id="test.newAction3"> </action> </objectContribution> </extension>
运行效果如下图所示:

[
本帖最后由 guoyibj 于 2009-10-16 22:30 编辑 ]
| 只看该作者  | |
justforregister 闭关**
精华贴数 2
个人空间 10
技术积分 88947 (6)
社区积分 33648 (43)
注册日期 2005-6-10
论坛徽章:154
|
|
| |
什么东东
| __________________
主营业务:
SAP NetWeaver Portal
SAP PI
SAP MDM
SAP Composite Environment(CE7.11&7.2)
SAP BPM
顺带帮朋友卖卖oracle数据库
招SAP basis 和xi
招人咯.....HP的职位,有兴趣的可以发邮件到justforregister@163.com
Senior R&D Manager (Quality Center) Senior R&D Manager (QTP) C++ Technical Lead (LR/QTP) Java/.NET Technical Lead (Quality Center) QA Technical Lead (QTP) QA Technical Lead (LoadRunner) Senior Software Engineer (.Net/C++) Senior Software Engineer (Java or C/C++) Software Engineer (Java/.NET) Software Engineer (C++/C#) Software QA Engineer QA Engineer Tech Support Engineer
| 只看该作者  | |
guoyibj
精华贴数 0
个人空间 0
技术积分 120 (17457)
社区积分 0 (2018937)
注册日期 2008-12-22
论坛徽章:0
|
|
justforregister 闭关**
精华贴数 2
个人空间 10
技术积分 88947 (6)
社区积分 33648 (43)
注册日期 2005-6-10
论坛徽章:154
|
|
| |
QUOTE:
原帖由
guoyibj 于 2009-10-16 20:54 发表
634362
nice job
| __________________
主营业务:
SAP NetWeaver Portal
SAP PI
SAP MDM
SAP Composite Environment(CE7.11&7.2)
SAP BPM
顺带帮朋友卖卖oracle数据库
招SAP basis 和xi
招人咯.....HP的职位,有兴趣的可以发邮件到justforregister@163.com
Senior R&D Manager (Quality Center) Senior R&D Manager (QTP) C++ Technical Lead (LR/QTP) Java/.NET Technical Lead (Quality Center) QA Technical Lead (QTP) QA Technical Lead (LoadRunner) Senior Software Engineer (.Net/C++) Senior Software Engineer (Java or C/C++) Software Engineer (Java/.NET) Software Engineer (C++/C#) Software QA Engineer QA Engineer Tech Support Engineer
| 只看该作者  | |
sqlwhy
精华贴数 0
个人空间 0
技术积分 377 (6335)
社区积分 42 (6817)
注册日期 2009-11-7
论坛徽章:0
|
|
| |
不错啊
呵呵
| __________________
| 只看该作者  | |
justforregister 闭关**
精华贴数 2
个人空间 10
技术积分 88947 (6)
社区积分 33648 (43)
注册日期 2005-6-10
论坛徽章:154
|
|
| |
这年头有人做插件吗
| __________________
主营业务:
SAP NetWeaver Portal
SAP PI
SAP MDM
SAP Composite Environment(CE7.11&7.2)
SAP BPM
顺带帮朋友卖卖oracle数据库
招SAP basis 和xi
招人咯.....HP的职位,有兴趣的可以发邮件到justforregister@163.com
Senior R&D Manager (Quality Center) Senior R&D Manager (QTP) C++ Technical Lead (LR/QTP) Java/.NET Technical Lead (Quality Center) QA Technical Lead (QTP) QA Technical Lead (LoadRunner) Senior Software Engineer (.Net/C++) Senior Software Engineer (Java or C/C++) Software Engineer (Java/.NET) Software Engineer (C++/C#) Software QA Engineer QA Engineer Tech Support Engineer
| |
开发 Eclipse 插件 如何创建、调试和安装插件  |  |
 |
级别: 初级 David Gallardo (david@gallardo.org), 软件顾问 2003 年 3 月 26 日 更新 2003 年 3 月 26 日
在本文中,David Gallardo 向您展示了如何使用 Plug-in Development Environment 的代码生成向导来创建 Eclipse 插件。您将学到如何在运行时工作台中运行和调试插件,并且在 Eclipse 中安装完成的插件。David 还研究了与打包插件相关的问题 ― 包括维护版本信息、以插件片段的形式更新功能,以及组合插件来创建完整的功能部件。
基于插件的体系结构 Eclipse 平台是 IBM 向开发源码社区捐赠的开发框架,它之所以出名并不是因为 IBM 宣称投入开发的资金总数 ― 4 千万美元 ― 而是因为如此巨大的投入所带来的成果:一个成熟的、精心设计的以及可扩展的体系结构。Eclipse 的价值是它为创建可扩展的集成开发环境提供了一个开放源码平台。这个平台允许任何人构建与环境和其它工具无缝集成的工具。 工具与 Eclipse 无缝集成的关键是插件。除了小型的运行时内核之外,Eclipse 中的所有东西都是插件。从这个角度来讲,所有功能部件都是以同等的方式创建的。从这个角度来讲,所有功能部件都是以同等的方式创建的。 但是,某些插件比其它插件更重要些。Workbench 和 Workspace 是 Eclipse 平台的两个必备的插件 ― 它们提供了大多数插件使用的扩展点,如图 1 所示。插件需要扩展点才可以插入,这样它才能运行。 图 1. Eclipse Workbench 和 Workspace:必备的插件支持 Workbench 组件包含了一些扩展点,例如,允许您的插件扩展 Eclipse 用户界面,使这些用户界面带有菜单选择和工具栏按钮;请求不同类型事件的通知;以及创建新视图。Workspace 组件包含了可以让您与资源(包括项目和文件)交互的扩展点。 当然,其它插件可以扩展的 Eclipse 组件并非只有 Workbench 和 Workspace。此外,还有一个 Debug 组件可以让您的插件启动程序、与正在运行的程序交互,以及处理错误 ― 这是构建调试器所必需的。虽然 Debug 组件对于某些类型的应用程序是必需的,但大多数应用程序并不需要它。 还有一个 Team 组件允许 Eclipse 资源与版本控制系统(VCS)交互,但除非您正在构建 VCS 的 Eclipse 客户机,否则 Team 组件,就象 Debug 组件一样,不会扩展或增强它的功能。 最后,还有一个 Help 组件可以让您提供应用程序的联机文档和与上下文敏感的帮助。没有人会否认帮助文档是专业应用程序必备的部分,但它并不是插件功能的必要部分。 上述每个组件提供的扩展点都记录在 Eclipse Platform Help 中,该帮助在 Platform Plug-in Developer 指南的参考部分中。乍一看,尤其是 API 参考大全的 Workbench 部分,一开始会令人望而却步。我们不会深入了解众多可用扩展点的详细信息,而只是粗略地看一个简单插件及其组件。
插件简介 创建插件最简单的方法是使用 Plug-in Development Environment(PDE)。PDE 和 Java Development Tooling(JDT)IDE 是 Eclipse 的标准扩展。PDE 提供了一些向导以帮助创建插件,包括我们将在这里研究的“Hello, world”示例。 从 Eclipse 菜单,选择 File=>New=>Other(或按 Ctrl-N),然后选择 Select 对话框左边的 Plug-in Development 向导。在 Select 对话框的右边,选择 Plug-in Project。按 Next。在下一屏上,输入项目名称;我使用了 com.example.hello。再次按 Next。在下一屏上,请注意,插件标识就与项目名称相同。使用项目名称作为插件标识可以将该插件与另一个插件的名称发生冲突的机会减到最小。再按一次 Next。下一屏让您选择是手工创建初始插件代码,还是运行代码生成向导。保留代码生成向导的缺省选项,选择“Hello, World”,然后按 Next,如图 2 所示。 图 2. 选择“Hello, World”代码生成向导 下一屏要求一些附加信息。请注意这一屏上的信息:它包含了插件名称、版本号、提供者名称和类名。这些是关于插件的重要信息,我们将在稍后研究。可以接受向导提供的缺省值。按 Next。在下一屏幕上,接受包名、类名和消息文本的缺省值。选择“Add the action set to the resource perspective”复选框。按 Finish。 如果接到通知:向导需要启用某些其它插件才能完成,那么按 OK。 过一会儿,向导将完成,而在您的工作区中将会有一个新的项目,名为 com.example.hello,如图 3 所示。 图 3. PDE 透视图:Welcome to Hello Plug-in 在 Package Explorer 中,工作台的左边是向导创建的一些东西的概述。大多数项都不引人关注:包括项目类路径中的许多 .jar 文件(这些包括插件和 Java 运行时所需的 Eclipse 类)、一个图标文件夹(包含了工具栏按钮的图形),以及 build.properties 文件(包含自动构建脚本所使用的变量)。 这里最有意思的东西是 src 文件夹,它包含了插件和 plugin.xml 文件的源代码 ― plug-in.xml 是插件的清单文件。我们将先查看 plugin.xml。
插件清单文件 插件清单文件 plugin.xml 包含了 Eclipse 将插件集成到框架所使用的描述信息。缺省情况下,当第一次创建插件时,会在清单编辑器区域中打开 plugin.xml。编辑器底部的选项卡让您可以选择关于插件的不同信息集合。Welcome 选项卡显示了消息“Welcome to Hello Plug-In”,并且简要讨论了所使用的模板和关于使用 Eclipse 实现插件的提示。选择“Source”选项卡可以让您查看 plugin.xml 文件的完整源代码。 让我们看看插件清单文件的各个部分。首先是关于插件的常规信息,包括它的名称、版本号、实现它的类文件的名称和 .jar文件名。 清单 1. 插件清单文件 ― 常规信息
<?xmlversion="1.0" encoding="UTF-8"?>
<plugin
id="com.example.hello"
name="Hello Plug-in"
version="1.0.0"
provider-name="EXAMPLE"
class="com.example.hello.HelloPlugin">
<runtime>
<library name="hello.jar"/>
</runtime>
| 接着,列出了我们的插件所需的插件: 清单 2. 插件清单文件 ― 必需的插件
<requires>
<import plugin="org.eclipse.core.resources"/>
<import plugin="org.eclipse.ui"/>
</requires>
| 列出的第一个插件 org.eclipse.core.resources 是工作区插件,但实际上我们的插件并不需要它。第二个插件 org.eclipse.ui 是工作台。我们需要工作台插件,因为我们将扩展它的两个扩展点,正如后面的 extension 标记所指出的。 第一个 extension 标记拥有点属性 org.eclipse.ui.actionSets。操作集合是插件添加到工作台用户界面的一组基值 ― 即,菜单、菜单项和工具栏。操作集合分组了基值,这样用户可以更方便地管理它们。例如,我们的 Hello 插件的菜单和工具栏项将出现在 Resource 透视图中,因为当在运行代码生成向导时,我们做了这样的选择。如果用户要更改它,可以使用 Window=>Customize Perspective 菜单选项从要在 Resource 透视图中显示的项中除去“Sample Action Set”。 图 4. 定制 Resource 透视图 操作集合包含了两个标记:menu 标记(描述菜单项应该出现在工作台菜单的什么位置,以及如何出现)和action 标记(描述它应该做什么)― 尤其是 action 标记标识了执行操作的类。注:这个类不是上面列出的插件类。 清单 3. 操作集合
<extension
point="org.eclipse.ui.actionSets">
<actionSet
label="Sample Action Set"
visible="true"
id="com.example.hello.actionSet">
<menu
label="Sample &Menu"
id="sampleMenu">
<separator
name="sampleGroup">
</separator>
</menu>
<action
label="&Sample Action"
icon="icons/sample.gif"
class="com.example.hello.actions.SampleAction"
tooltip="Hello, Eclipse world"
menubarPath="sampleMenu/sampleGroup"
toolbarPath="sampleGroup"
id="com.example.hello.actions.SampleAction">
</action>
</actionSet>
</extension>
| 许多菜单和操作属性的目的相当明显 ― 例如,提供工具提示文本和标识工具栏项的图形。但还要注意 action 标记中的 menubarPath:这个属性标识了 menu 标记中定义的哪个菜单项调用 action 标记中定义的操作。有关这个和其它工作台扩展点的详细信息,请参考 Platform Plug-in Developer Guide,尤其是“Plugging into the workbench”章节(可以从 Eclipse 的帮助菜单中获取该指南)。 由于我们选择了将插件添加到 Resource 透视图,于是生成了第二个 extension 标记。这个标记会导致当 Eclipse 第一次启动并装入我们的插件时,将插件添加到 Resource 透视图。 清单 4. extension 标记
<extension
point="org.eclipse.ui.perspectiveExtensions">
<perspectiveExtension
targetID="org.eclipse.ui.resourcePerspective">
<actionSet
id="com.example.hello.actionSet">
</actionSet>
</perspectiveExtension>
</extension>
</plugin>
| 如果忽略这最后一个 extension,用户就需要使用 Window=>Customize Perspective 将插件添加到 Resource(或其它)透视图。
插件源代码 代码生成向导生成了两个 Java 源文件,打开 PDE Package Explorer 中的 src 文件夹就可以看到它们。第一个文件 HelloPlugin.java 是插件类,它继承了 AbstractUIPlugin 抽象类。HelloPlugin 负责管理插件的生命周期,在更为扩展的应用程序中,它负责维护诸如对话框设置和用户首选项等内容。HelloPlugin 要做的事就这么多: 清单 5. HelloPlugin
packagecom.example.hello.actions;
import org.eclipse.ui.plugin.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.resources.*;
import java.util.*;
/**
* The main plugin class to be used in the desktop.
*/
public class HelloPlugin extends AbstractUIPlugin {
//The shared instance.
private static HelloPlugin plugin;
//Resource bundle.
private ResourceBundle resourceBundle;
/**
* The constructor.
*/
public HelloPlugin(IPluginDescriptor descriptor) {
super(descriptor);
plugin = this;
try {
resourceBundle= ResourceBundle.getBundle(
"com.example.hello.HelloPluginResources");
} catch (MissingResourceException x) {
resourceBundle = null;
}
}
/**
* Returns the shared instance.
*/
public static HelloPlugin getDefault() {
return plugin;
}
/**
* Returns the workspace instance.
*/
public static IWorkspace getWorkspace() {
return ResourcesPlugin.getWorkspace();
}
/**
* Returns the string from the plugin's resource bundle,
* or 'key' if not found.
*/
public static String getResourceString(String key) {
ResourceBundle bundle= HelloPlugin.getDefault().getResourceBundle();
try {
return bundle.getString(key);
} catch (MissingResourceException e) {
return key;
}
}
/**
* Returns the plugin's resource bundle,
*/
public ResourceBundle getResourceBundle() {
return resourceBundle;
}
}
| 第二个源文件 SampleAction.java 包含的类将执行在清单文件的操作集合中指定的操作。SampleAction 实现了 IWorkbenchWindowActionDelegate 接口,它允许 Eclipse 使用插件的代理,这样不是在万不得已的情况下,Eclipse 就无需装入插件(这项优化工作使在装入插件时发生内存和性能方面的问题降到最低)。IWorkbenchWindowActionDelegate 接口方法使插件可以与代理进行交互: 清单 6. IWorkbenchWindowActionDelegate 接口方法
package com.example.hello.actions;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.IWorkbenchWindowActionDelegate;
import org.eclipse.jface.dialogs.MessageDialog;
/**
* Our sample action implements workbench action delegate.
* The action proxy will be created by the workbench and
* shown in the UI. When the user tries to use the action,
* this delegate will be created and execution will be
* delegated to it.
* @see IWorkbenchWindowActionDelegate
*/
public class SampleAction implements IWorkbenchWindowActionDelegate {
private IWorkbenchWindow window;
/**
* The constructor.
*/
public SampleAction() {
}
/**
* The action has been activated. The argument of the
* method represents the 'real' action sitting
* in the workbench UI.
* @see IWorkbenchWindowActionDelegate#run
*/
public void run(IAction action) {
MessageDialog.openInformation(
window.getShell(),
"Hello Plug-in",
"Hello, Eclipse world");
}
/**
* Selection in the workbench has been changed. We
* can change the state of the 'real' action here
* if we want, but this can only happen after
* the delegate has been created.
* @see IWorkbenchWindowActionDelegate#selectionChanged
*/
public void selectionChanged(IAction action, ISelection selection) {
}
/**
* We can use this method to dispose of any system
* resources we previously allocated.
* @see IWorkbenchWindowActionDelegate#dispose
*/
public void dispose() {
}
/**
* We will cache window object in order to
* be able to provide parent shell for the message dialog.
* @see IWorkbenchWindowActionDelegate#init
*/
public void init(IWorkbenchWindow window) {
this.window = window;
}
}
|
  |

| 运行和调试插件 当开发 Eclipse 的插件时,必须停止 Eclipse 并用新的插件重新启动它以便进行测试和调试,这很笨拙。幸好,Eclipse PDE 提供了一个自托管(self-hosted)的开发环境,它让您无需将插件安装在工作台的单独实例中即可运行。 要运行 Hello 插件,选择 Run=>Run As=>Run-time Workbench 来启动另一个 Workbench 实例,而该实例添加了插件的菜单选项和工具栏,如图 5 所示。 图 5. 在运行时工作台中运行的 Hello 插件 我们可以通过单击工具栏按钮或从“Sample Menu”菜单激活插件。任何一种方法都会生成一个框,其标题是“Hello Plug-in”,内容是“Hello, Eclipse world”,以及一个 OK 按钮,按该按钮可以关闭这个框。 通过选择 Run=>Debug As=>Run-time Workbench,按类似的方法调试插件。这次,当插件在第二个工作台实例中运行时,我们可以在最初的工作台中单步执行源代码,以及检查变量等。 一旦插件经过测试并准备发布,我们就需要将它适当打包,以便在 Eclipse 中安装。
打包插件 Eclipse 在启动时会查看其插件目录来确定要装入哪些插件。要安装插件,我们需要在插件目录中创建一个子目录,并将程序文件和清单文件复制到那里。建议目录名称能表示插件的标识,并且后面跟下划线和版本号,但是这种做法不是必需的。假设 Eclipse 安装在 C:/eclipse 中;我们要创建一个目录: C:/eclipse/plugins/com.example.hello_1.0.0. 按照 Java 程序的标准,我们的程序文件需要归档到 .jar文件中 — 我们的插件清单文件,您也许记得它包含这个项:
<runtime>
<library name="hello.jar"/>
</runtime>
| 要创建 hello.jar 文件,我们可以通过突出显示项目名称,并从 Eclipse 菜单选择 File=>Export,以导出插件文件。选择 JAR 文件作为导出方式,按 Next,然后浏览到我们为它创建的目录。下一步,我们还需要将 plugin.xml 文件复制到这个目录。也可以使用 File=>Export 菜单选项(但请要记住选择 File System 作为导出目的地)。 这就是安装插件所需的全部操作,但您将需要停止并重新启动 Eclipse,以便能识别这个新的插件。从帮助菜单中选择“About Eclipse Platform”,可以找到关于已安装插件的信息,包括版本号。在出现的屏幕上有一个按钮是 Plug-in Details;向下滚动列表来寻找 Hello 插件及其版本号。
更新插件版本 在目录名称中包含版本号的目的是允许在同一台机器上共存某个插件的多个版本(每次只装入一个版本)。我们可以通过创建一个 Hello 插件的已更新版本来看看这是如何工作的:例如,将 plugin.xml 文件中的版本号更改成“1.0.1”,然后将 SampleAction.java 中的文本更改成“New and improved Hello, Eclipse world”。从 Eclipse 菜单中选择 Project=> Rebuild All。下一步,将项目文件以 JAR 形式导出到新的插件目录,例如,com.example.hello_1.0.1。将修订过的 plugin.xml 文件复制到同一个目录中。当停止并重新启动 Eclipse 时,只会装入已更新的插件。
插件片段和功能部件 Eclipse 由插件组成,但在开发 Eclipse 的插件时,还要慎重考虑另外两个级别的组件 ― 插件片段和功能部件。 插件片段(如名称所暗示的)是完整插件的组成部分 ― 目标插件。片段提供的功能与目标插件的功能合并。片段可以用于将插件本地化成各种语言;在无需形成一个全新发行版的情况下,以增量形式将功能部件添加到现有插件,或者提供特定于平台的功能。在许多方面,片段与插件一样。主要的区别就是片段没有插件类 ― 片段的生命周期由其目标插件管理。此外,片段的清单文件叫作 fragment.xml,它列出了目标插件的标识和版本号,以及片段的标识和版本号。 另一方面,插件功能部件根本不包含编码。在 Eclipse 体系结构术语中,功能部件是将一组相关插件打包到完整的产品中。例如,JDT 是包含了象 Java 编辑器、调试器和控制台这样的插件的功能部件。名为 feature.xml 的清单文件描述了一个功能部件归档文件。在其中,该清单文件包含了对该功能部件所包含的插件和其它资源的引用、关于如何更新该功能部件的信息、版权信息和许可证信息。 在 Eclipse 中,主功能部件设置了 Eclipse 平台的外观。主功能部件旨在确定诸如给予 Eclipse 其身份的闪屏和其它特征之类的东西。Eclipse 只允许一个主功能部件。用这种方式,通过创建一组插件,将它们打包到功能部件中,并且使这个功能部件成为主功能部件,就可以重新创建 Eclipse 的品牌,并将它用于创建全新且不同的产品。如果从 Eclipse.org 下载,缺省主功能部件是 eclipse.org.platform。
后续步骤 在插件的介绍里我们只是稍微了解一些插件的必要用法。学习插件的更多知识的最佳参考资料是 Plug-in Developer's Guide,可以从 Eclipse 中的帮助菜单中获得该指南。该文档包含了编程指南、Eclipse API 和插件扩展点的参考大全、Eclipse.org 上可用的编程示例的指南,以及常见问题列表。另一个优秀参考资料是 Eclipse 本身的源代码。根据您的兴趣,您也许想要查找一些示例,以了解不同工作台功能部件(如视图和编辑器)是如何扩展的,或者如何使用 SWT(Eclipse 图形 API)。此外,下面的参考资料可以帮助您学到更多知识。 参考资料
关于作者
 | | |  | David Gallardo 是一名独立软件顾问和作家,他的专长是软件国际化、Java Web 应用程序和数据库开发。他成为专业软件工程师已经有十五年了,他拥有许多操作系统、编程语言和网络协议的经验。他最近在一家企业对企业电子商业公司 TradeAccess, Inc 从事先进的数据库和国际化开发。在这之前,他是 Lotus Development Corporation 的 International Product Development 组中的高级工程师,负责开发为 Lotus 产品(包括 Domino)提供 Unicode 和国际语言支持的跨平台库。可以通过 david@gallardo.org与 David 联系。 | |
Eclipse简介和插件开发  |  |
 |
级别: 初级 ** (zy_coding@tom.com), J2EE程序员 2004 年 11 月 03 日
Eclipse 是一个很让人着迷的开发环境,它提供的核心框架和可扩展的插件机制给广大的程序员提供了无限的想象和创造空间。目前网上流传相当丰富且全面的开发工具方面的插件,但是Eclipse已经超越了开发环境的概念,可以想象Eclipse将成为未来的集成的桌面环境。目前的Eclipse本身就具备资源管理和外部程序的功能,加上无所不能的插件,将构成一个丰富多彩的工作环境而不仅仅是一个IDE。
1.Eclipse简介和插件开发 Eclipse 是一个很让人着迷的开发环境,它提供的核心框架和可扩展的插件机制给广大的程序员提供了无限的想象和创造空间。目前网上流传相当丰富且全面的开发工具方面的插件,但是Eclipse已经超越了开发环境的概念,可以想象Eclipse将成为未来的集成的桌面环境。目前的Eclipse本身就具备资源管理和外部程序的功能,加上无所不能的插件,将构成一个丰富多彩的工作环境而不仅仅是一个IDE。对于程序员来说,没有什么比可以随心所欲的定制的工作环境更重要,你的决心,勇气和创造力在与别人分享成果的过程中一览无余。好了,你是不是心动了,如果你已经对Eclipse有一定的认识,那么,和我一起打造自己的个性化工作环境吧,首先我们一起开发一个天气预报的插件,然后我们打造属于自己的邮件快速监控功能。 以下的工作基于一定的前提,那就是你是一名Java程序员,你很欣赏并正开始使用Eclipse这个超酷的工作环境,别忘了下载最新版的Eclipse3.0,本文基于Eclipse3.0开发。
2.天气预报插件 如果你已经厌倦了总是要登录某些网站从相关网页上获取信息,这里有一个让你通过Eclipse快速获取信息的新方法。让我们从头开始,做一个属于自己的天气预报插件吧,你的Eclipse将具有天气预报功能,是不是很酷呢? 在这一部分,我们将要实现一个Eclipse插件,他可以在任何我们想知道的时候通过简单的点击鼠标告诉我们本地区的天气预报,这当然很刺激。对于一个程序员而言,事情就应该如此。让我们开始吧,我们首先要定义一个插件,把他加到菜单和工具栏中。对于没有插件开发经验的你,可以参考《 开发 Eclipse 插件》,树立基本的插件开发意识,当然,本文将详细的辅助你完成这一创造性的工作。 2.1最基础的插件 你可以完全参考《 开发 Eclipse 插件》的插件示例,制作你的第一个 hello Eclipse 插件,幸运的是,Eclipse3.0完全考虑到你的需求,通过菜单 File -> New-> Other ->Plug-in Project,输入项目名称,next出现对话框,只要在插件名处输入"muplugin",next 以后选择 "Hello,World"的插件模板你可以直接新建一个名为myplugin的最简单的插件,但其实我们的天气预报并不比它复杂多少,建完改插件以后的效果如下图。 现在,将项目作为运行时工作台运行(run - run as runtime workbench),在一个全新的Eclipse窗口中,通过点击菜单 sample menu 的sample Action或者工具栏中的圆形Eclipse 图标,你将看到如下效果的对话框。 到此为止,天气预报插件的原始版做成了,通过修改plugin.xml,我们将菜单改成中文形式,需要修改的地方就2处,详见表格。
<actionSet
label="Sample Action Set"
visible="true"
id="myplugin.actionSet">
<menu
label="我的空间"
id="sampleMenu">
<separator
name="sampleGroup">
</separator>
</menu>
<action
label="天气预报"
icon="icons/sample.gif"
class="myplugin.actions.SampleAction"
tooltip="Hello, Eclipse world"
menubarPath="sampleMenu/sampleGroup"
toolbarPath="sampleGroup"
id="myplugin.actions.SampleAction">
</action>
| 此时在运行时工作台,我们的菜单已经改变。 2.2用VisualEditer制作天气预报对话框 虽然菜单是天气预报,但是我们需要的不是hello Eclispe对话框,我们需要的是告诉我们天气的对话框,当然需要我们从头开始,于是我们需要重新构建一个对话框,这个就需要 Visual Editor来帮助进行界面的开发(关于Visual Editer参考《 Build GUIs with the Eclipse Visual Editor project》) 。我们将使用Visual Editor实现一个Swing对话框,当然只用VE做一个对话框是有点大材小用,但是作为起点,已经合适了。 首先参考《 Build GUIs with the Eclipse Visual Editor project》构建Visual Editer开发环境,当一切准备齐全,鼠标右键点击PackgeExpoler中的 "muplugin.actions"java文件,从弹出式菜单中选择 new->other->VisualClass,新建一个可视化的类,弹出界面如下图: 选择next,然后在name中输入WeatherDialog,这个就是我们用来显示天气预报的dialog 选择该对话框的超类为javax.swing.JDiaog,点击Finish按钮。等待一段时间后,我们的对话框就基本生成了,鼠标点击左上角图标,直接输入天气预报就是对话框的标题,同时 我们可以看到左侧的VisualEditor面板。 然后我们将该对话框于与刚才的天气预报菜单连接找到SampleAction的run函数,如下所示:
public void run(IAction action) {
MessageDialog.openInformation(
window.getShell(),
"Myplugin Plug-in",
"Hello, Eclipse world");
}
| 替换成如下代码
public void run(IAction action)
{
WeatherDialog wd=new WeatherDialog();
wd.setSize(400, 335);
wd.show();
}
| 此时,点击菜单运行,我们的对话框看起来象这个样子,在此基础上我们还要在上面增加天气预报信息 2.3增加天气预报功能 下面的部分是重点,我们将使用具有解析Html功能的Swing组件JEditPane,来获取网络上的现成的天气预报信息,根据上图,从 VisualEditor的面板中Swing Components组点击JEditPane,加入到对话框中。并修改对话框代码使得最终的代码如下:
/*
* Created on 2004-9-23
* */
package myplugin;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
/**
* <p>Title: WatherDialog</p>
* <p>Description: 这个是对话框类,用于显示指定城市的当天的天气预报</p>
* <p>Copyright: Copyright (c) 2004</p>
* <p>Company:UF SOFT</p>
* @author **
* @version 1.0
*/
public class WatherDialog extends JDialog
{
String city="北京";
private JEditorPane jEditorPane = null;
/**
* This method initializes
* /
public WatherDialog(String city)
{
super();
this.city=city;
initialize();
}
/**
* This method initializes this
* @return void
*/
private void initialize()
{
this.setContentPane(getJEditorPane());
try
{
//构建URL对象
URL url =new URL("http://weather.news.sina.com.cn//cgi-bin/figureWeather/simpleSearch.cgi?city="+city);
String temp="";
BufferedReader in
= new BufferedReader(new InputStreamReader(url.openStream()));
//使用openStream得到一输入流并由此构造一个BufferedReader对象
String inputLine;
//从输入流不断的读数据,直到读完为止
while ((inputLine = in.readLine()) != null)
temp=temp+inputLine+"/n";
//关闭输入流
in.close();
String weather
=temp.substring ( temp.indexOf( "<body"),
temp.lastIndexOf( "body>")+5);
this.jEditorPane .setText(weather);
}
catch (Exception e)
{
e.printStackTrace();
}
this.setTitle("天气预报");
this.setSize(400, 166);
}
/**
* This method initializes jEditorPane
*
* @return javax.swing.JEditorPane
*/
private JEditorPane getJEditorPane()
{
if (jEditorPane == null)
{
jEditorPane = new JEditorPane();
jEditorPane.setContentType( "text/html");
}
return jEditorPane;
}
} // @jve:decl-index=0:visual-constraint="70,19"
| 以上代码中最关键的部分就是对话框中的JEditorPane对象,在初始化时,从一个URL 获取天气预报信息,表现为Html标记片段,不用解析,直接调用JEditorPane的setText 方法,就可以将Html格式的信息直接按解析过的方式显示,也就是天气预报信息了, 此时Action中的调用需要做修改
public void run(IAction action)
{
WeatherDialog wd=new WeatherDialog("北京");
wd.setSize(400, 335);
wd.show();
}
| 现在以运行时工作台的方式运行,点击天气预报菜单,可以看到下图: 如果你在上海或者其他城市,试着修改city参数为"上海",再次运行,你将发现,你仍然能够得到该城市的天气预报(这里我们从网站上提取的信息,有点投机取巧了)。值得注意的是,Xmethod网站提供了一个天气预报的WebService,可惜只有美国的城市,不然我们可以使用Web Service调用获取天气预报,将会更酷。 现在运行是工作台已经具备了天气预报的功能,还需要更进一步,将改插件导出发布,拷贝到Eclipse根目录的plugins目录中,重新启动(具体参见Eclipse帮助)。现在你自己的Eclipse,就具备了天气预报的功能,只要你点击鼠标,就可以在编程之余轻松的获取天气信息。 除非你的老板认为你在工作时间随时了解天气情况不是一个好主意,我认为你完全可以将这个插件纳入个人收藏的插件之列。你也可以在此基础上扩展,增加一些配置文件和属性设置,定制出满足自己要求的插件。如果能够增加信息的自动过滤和筛选,那将是一次很愉快的体验,如果你有时间和兴趣,不妨一试。
3.邮件快速监控插件 现在你的工作因为Eclipse而更加惬意,更具创造力,那么你还有什么不满?你是否厌倦了各种邮件客户端随时随地的骚扰你呢?你希望你在高兴的时候适时的了解一下邮件的概况?好了,既然想到了为什么犹豫呢,因为你是程序员,你就是要用Eclipse享受完全DIY的乐趣。 3.1生成插件 本部分我们将在以上myplugin插件的基础上增加一个邮件过滤显示的对话框,类似的我们通过VisualEditer创建一个名为MailDialog的对话框,并增加一个JEditPane用来显示邮箱中我们关注的信息。 修改plugin.xml,增加一个"我的邮件"菜单
<action
label="邮件信息"
icon="icons/sample.gif"
class="myplugin.actions.MailAction"
tooltip="邮件信息"
menubarPath="sampleMenu/sampleGroup"
toolbarPath="sampleGroup"
id="myplugin.actions.MailAction">
</action>
| 现在,你知道要创建一个MailAction的Action类,并在在Run中增加如下代码
MailConfig mail=new MailConfig();
String popServer="server";
String popUser="zhaoyong";
String popPassword="1234";
//设置需要过滤的关键字:发件人和邮件主题
String [] strFrom=new String[] {"zhaoyong"};
String [] strSubject=new String[] {"测试"};
MailConfig[] mc =new MailConfig [] { mail };
MailDialog md=new MailDialog(mc);
System.err.println("run run run ") ;
md.setSize(400, 335);
md.show();
| 以上的代码编译不会通过,但是别着急,慢慢来,很快了。 3.2构建邮件监控对话框 当然你需要建立一个MailConfig类用来表示一个邮箱的具体设置已及相关信息,这里就不在累述说明,详情参见参考资料中的代码。需要说明的式MailConfig除了要记录一个邮箱的地址,用户名和密码外,还提供2个关键字数组,如果为空,不加过滤,如果关键字有值,系统会根据发件人和邮件标题中是否包含关键字来进行显示邮件信息,已保证你的绝对自由。 首先我们需要实现一个MailConfig类,表示邮件配置,每个MailConfig的对象代表一个邮件帐户,我们的系统将能显示多个邮箱的配置,每个MailConfig中使用一个数组来保存需要过滤的收件人和邮件地址。 MailConfig类的中的变量如下:
String popServer;
String popUser;
String popPassword;
//设 置 需 要 过 滤 的 关 键 字 : 发 件 人 和 邮 件 主 题
String [] strFrom;
String [] strSubject;
//是 否 显 示 邮 件 内 容
boolean isViewContent=false;
| 同样,我们将使用一个对话框来显示邮件信息,MailDialog需要引用javaMail.jar,和activation.jar这两个类包,确保已经有这两个类包并加入到项目的类路径中。最后的MailDialog代码如下:
package myplugin;
import java.io.IOException;
import java.util.Properties;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.internet.InternetAddress;
import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JTextPane;
/**
* @author zhaoyong
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class MailDialog extends JDialog
{
private JEditorPane jEditorPane = null;
private JTextPane jTextPane = null;
//可以显示多个邮件配置
MailConfig[] mc= null;
/**
* This method initializes
* 构造函数
* @param mc : 需要显示的多个邮箱配置对象。
*/
public MailDialog(MailConfig[] mc)
{
super();
if(mc!=null)
this.mc = mc;
else
System.err.println("邮件配置错误!") ;
initialize();
}
/**
* This method initializes this
* 初始化
* @return void
*/
private void initialize()
{
try
{
//设定显示内容的面板
this.setContentPane(getJTextPane());
//取得所有的新邮件信息
String s= getAllMailInfo();
//将信息显示在对话框中
this.jTextPane .setText(s);
this.setTitle("邮件信息");
this.setSize(251, 100);
}
catch (Exception e)
{
//发生错误显示错误信息
this.jTextPane .setText(e.toString());
e.printStackTrace();
}
}
/**取得所有的邮箱的需要监控的邮件信息
*
* @return String
*/
private String getAllMailInfo()
{
String allMailInfo="";
if (mc.length <1)
allMailInfo="没有配置邮箱!";
else
{
for(int i=0;i<mc.length;i++)
{
//循环获取每个邮箱的邮件信息
allMailInfo=allMailInfo+getMailInfo(mc[i]);
}
}
//还没有收到相关的邮件
if (allMailInfo.trim().length() ==0)
allMailInfo="未检测到相关新邮件!";
return allMailInfo;
}
/*
*得到一个邮箱中满足条件的所有新邮件的字符串形式
**/
private String getMailInfo(MailConfig mc)
{
//最终输出的邮件信息
String mailInfo="";
//每个邮箱服务器上的Store和Folder对象
Store store=null;
Folder folder=null;
try
{
Properties props = System.getProperties();
//与邮件服务器生成一个Session
Session session = Session.getDefaultInstance( props,null);
//给出服务器,用户名,密码连接服务器
store = session.getStore("pop3");
store.connect(mc.getPopServer(), mc.getPopUser(),mc.getPopPassword());
//取得默认的邮件Folder
folder = store.getDefaultFolder();
if (folder == null)
throw new Exception("No default folder");
//取得收件箱
folder = folder.getFolder("INBOX");
if (folder == null)
throw new Exception("No POP3 INBOX");
//以只读方式打开收件箱
folder.open(Folder.READ_ONLY);
//获取所有新邮件并处理
Message[] msgs = folder.getMessages();
for (int i = 0; i < msgs.length; i++)
{
Message message= msgs[i];
//取得每封邮件的信息,需要引用MailConfig对象进行关键字过滤
mailInfo = mailInfo+ getMessageInfo( message,mc);
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
//安全的关闭邮件服务器资源
try
{
if (folder!=null) folder.close(true);
if (store!=null) store.close();
}
catch (Exception ex2) {ex2.printStackTrace();}
}
return mailInfo;
}
/**
* 得到一封邮件的信息,需要根据MailConfig过滤
* @param mailInfo
* @param message
* @return 邮件信息
* @throws MessagingException
* @throws IOException
*/
private String getMessageInfo( final Message message ,final MailConfig mc)
throws MessagingException, IOException
{
//返回的改邮件信息
String mailInfo="";
String from=((InternetAddress)message.getFrom()[0]).getPersonal();
if (from==null)
from=((InternetAddress)message.getFrom()[0]).getAddress();
String subject=message.getSubject();
//如果满足过滤信息则显示,否则返回空
if(isElementinString(from,mc.getStrFrom())
||isElementinString(subject,mc.getStrSubject()) )
{
mailInfo=mailInfo+"发件人 : "+from+"/n";
mailInfo=mailInfo+"邮件主题 : "+subject+"/n";
mailInfo=mailInfo+"发送时间 : "+message.getSentDate() +"/n";
//如果显示内容,则打印内容
if(mc.isViewContent)
mailInfo=mailInfo+message.getContent() +"/n";
mailInfo=mailInfo+"------------------------------------/n";
}
return mailInfo;
}
private JTextPane getJTextPane()
{
if (jTextPane == null)
{
jTextPane = new JTextPane();
}
return jTextPane;
}
/**
* 判断目标关键字数组中是否有指定的字符串,进行过滤
* @param targetStr :
* @param keys :
* @return 如果有,返回true, 否则返回false
*/
private boolean isElementinString(String targetStr,String [] keys)
{
//没指定过滤条件,显示所有
if (keys==null)
return true;
//指定字符串为空,直接返回false
if (targetStr==null)
return false;
for(int i=0;i<keys.length ;i++)
{
if (targetStr.indexOf(keys[i])>-1)
return true;
}
return false;
}
}
// @jve:decl-index=0:visual-constraint="10,10"--说明,这是Visual Editor添加的控制信息
| 以上代码的注释已经保证你能够看清楚,这里就不加累述,有兴趣的可以自己试试,体验一切尽在掌握的快感。当然这个例子做的实在简单,因此也为你的进一步开发留有足够的余地。 3.3打包和发布 到此,在mypulgin中增加了邮件信息菜单和对话框,系统的plugin.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin
id="myplugin"
name="Myplugin Plug-in"
version="1.0.0"
provider-name=""
class="myplugin.MypluginPlugin">
<runtime>
<library name="myplugin.jar">
<export name="*"/>
</library>
<library name="lib/javaMail.jar">
<export name="*"/>
</library>
<library name="lib/activation.jar">
<export name="*"/>
</library>
</runtime>
<requires>
<import plugin="org.eclipse.ui"/>
<import plugin="org.eclipse.core.runtime"/>
</requires>
<extension
point="org.eclipse.ui.actionSets">
<actionSet
label="Sample Action Set"
visible="true"
id="myplugin.actionSet">
<menu
label="我的空间"
id="sampleMenu">
<separator
name="sampleGroup">
</separator>
</menu>
<action
label="天气预报"
icon="icons/sample.gif"
class="myplugin.actions.SampleAction"
tooltip="Hello, Eclipse world"
menubarPath="sampleMenu/sampleGroup"
toolbarPath="sampleGroup"
id="myplugin.actions.SampleAction">
</action>
<action
label="邮件信息"
icon="icons/sample.gif"
class="myplugin.actions.MailAction"
tooltip="邮件信息"
menubarPath="sampleMenu/sampleGroup"
toolbarPath="sampleGroup"
id="myplugin.actions.MailAction">
</action>
</actionSet>
</extension>
</plugin>
| 实际上,我们在一个插件中加入了2个功能,因此就实现了我们的开发环境的自我扩展和定制。同样,参考Eclipse的帮助,你可以轻松的再次将插件打包导出,并将其加入自己的Eclipse 的plugins目录(可能需要解压缩),或通过help菜单的Update选项进行安装,注意导出时需要选定相关的类包。重新启动,你将发现自己的IDE已经多了自己的菜单,开发环境已经随着自己的意愿在改变了,程序员天生的满足感油然而生。 现在,你可以在需要的时候点击菜单,了解你希望监控的邮件情况或者最近的天气情况,一切轻松的尽在掌握,Eclipse的插件,就是这样全能。
4.总结 那么,聪明的你有没有发现什么问题,对,上面的东西太粗糙,太简单了,你可以做进一步的优化设计和功能加强,比如,自己增加邮件配置文件而不是写在代码里面,动态监控弹出邮件预警(通过事先设定的紧急状态),你也许还会想起来很多的新的主意,比如我为什么不能有个能看电影的插件?或是Eclipse中飘出动听的音乐?别急,这些不一定需要你亲手去做, http://sourceforge.net/projects/rocexwang/有一个播放器插件,但是现在仅能播放音乐,国外已经有人用Eclipse开发游戏,也有人用Eclipse来做MIS系统的。http://www.matrix.org.cn/forum_view.asp?forum_id=25&view_id=10510 有一个国人开发的俄罗斯方块游戏,虽然简单了一点。当然,通过网址 http://eclipse-plugins.2y.net/eclipse/index.jsp和 http://www.eclipseplugincentral.com/你可以找到很多的插件,如果你知道什么更好的插件,请告诉我。 Eclipse提供了一个纯的框架和插件结构,使得开发任何功能的插件都能成为现实。本文介绍了2个有趣的Eclipse插件的开发,可以使我们的工作环境增加了两个可爱的小功能,同时也使得你具备了基础的插件开发能力,借助Eclipse的强大功能,从此你可以把你的任何想法变为现实。同时请保持与别人的交流,我会很乐意了解你的新奇的插件,并收藏和学习任何好的插件,打造一个完全属于自己的个性化的开发环境。Eclipse将在不久的将来成为一个全能的Platform,这一点在全世界数以万计的开发人员的手中,正一点一点变为现实。 在这里下载代码: myplugin.rar,这里打包的是整个myplugin项目,解压缩后导入Eclipse,你可能需要重新配置类路径等工作。 |