<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.onmousedown=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.onmouseover=this.SubMenus[i].MouseOver;
tempTr.onmouseout=this.SubMenus[i].MouseOut;
tempTr.onclick=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.onload=function()
{
Menu.Config.FirstMenu.Create();
document.oncontextmenu=function(e)
{
Menu.Config.FirstMenu.Hidden();
e=e?e:event;
Menu.Config.FirstMenu.Show(e);
return false;
}
document.onmousedown=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="添加新菜單" onclick="add()">
<input type="button" value="把關機修改成關雞^_^" onclick="change()">
<input type="button" value="刪除頂菜單" onclick="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的職位,有興趣的可以發郵件到 [email protected]
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的職位,有興趣的可以發郵件到 [email protected]
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的職位,有興趣的可以發郵件到 [email protected]
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 ([email protected]), 軟件顧問
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 和國際語言支持的跨平臺庫。可以通過 [email protected]與 David 聯繫。
|
|
Eclipse簡介和插件開發
|
|
|
級別: 初級
** ([email protected]), 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,你可能需要重新配置類路徑等工作。
|