使用TreeViewer貢獻(xiàn)視圖(根據(jù)《Eclipse入門到精通》中的例子進(jìn)行的改編)
作者:李紅霞 2005-8-13
本文章允許轉(zhuǎn)載,但請(qǐng)要求注明文章作者及出處
一 創(chuàng)建插件項(xiàng)目
創(chuàng)建一個(gè)插件項(xiàng)目example.my.treeview,這個(gè)例子將向eclipse貢獻(xiàn)一個(gè)視圖,這個(gè)視圖采用樹(Treeviewer)來實(shí)現(xiàn)。
下圖是本例的文件清單
<抱歉,圖片傳不上來>
+ example.my.treeview
+ src
? + example.my.treeview
? ? - TreeviewPlugin.java
? + exampe.my.treeview.data
? ? - CityEntity.java
? ? - CountryEntity.java
? ? - DataFactory.java
? ? - PeopleEnrity.java
? + example.my.treeview.internal
? ? - ITreeEntry.java
? ? - TreeViewerContentProvider.java
? ? - TreeViewerLabelProvider.java
? ? - TreeViewPart.java
? + JRE System Library
? + Plug-in dependencies
? + META-INF
? ? - MENIFEST.MF
? - build.properties
? - plugin.xml
二 準(zhǔn)備數(shù)據(jù)模型
首先我們準(zhǔn)備數(shù)據(jù)模型,這些數(shù)據(jù)模型都保存在example.my.treeview.data這個(gè)包中
我們定義一個(gè)接口ItreeEntry,這個(gè)接口將定義樹中每個(gè)節(jié)點(diǎn)共同特征(名稱和子節(jié)點(diǎn)),代碼如下
package example.my.treeview.internal;
import java.util.List;
public interface ITreeEntry {
? ? ?public String getName();
? ? ?public void setName(String name);
? ? ?//設(shè)置得到子節(jié)點(diǎn)的集合
? ? ?public void setChildren(List children);
? ? ?public List getChildren();
}
這里涉及的實(shí)體一共有3個(gè),以下是他們的代碼
package example.my.treeview.data;
import java.util.List;
import example.my.treeview.internal.ITreeEntry;
public class CityEntity implements ITreeEntry{
? ? ?private Long id;//唯一識(shí)別碼
? ? ?private String name;//城市名
? ? ?private List peoples;//城市中的人
? ? ?public CityEntity(){}
? ? ?public CityEntity(String name){this.name=name;}
? ? ?public Long getId() {return id;}
? ? ?public void setId(Long id) {this.id = id;}
? ? ?public String getName() {return name;}
? ? ?public void setName(String name) {this.name = name;}
? ? ?public List getChildren() {return peoples;}
? ? ?public void setChildren(List peoples) {
? ? ? ? ? ?this.peoples = peoples;
? ? ?}
}
package example.my.treeview.data;
import java.util.List;
import example.my.treeview.internal.ITreeEntry;
public class CountryEntity implements ITreeEntry{
? //唯一識(shí)別碼,在數(shù)據(jù)庫里常為自動(dòng)遞增的ID列
? ? ?private Long id; ? ? ?
private String name;//國家名
//此國家所包含的城市的集合,集合元素為City對(duì)象
? ? ?private List cities; ? ? ?
? ? ?//兩個(gè)構(gòu)造函數(shù)
? ? ?public CountryEntity(){}
? ? ?public CountryEntity(String name){this.name = name;}
? //相應(yīng)的get和set方法
? ? ?public List getChildren() {return cities;}
? ? ?public void setChildren(List cities) {this.cities = cities;}
? ? ?public Long getId() {return id;}
? ? ?public void setId(Long id) {this.id = id;}
? ? ?public String getName() {return name;}
? ? ?public void setName(String name) {this.name = name;}
}
package example.my.treeview.data;
import java.util.List;
import example.my.treeview.internal.ITreeEntry;
public class PeopleEntity implements ITreeEntry{
? ? ?private String name;
? ? ?public PeopleEntity(){}
? ? ?public PeopleEntity(String name){this.name=name;}
? ? ?public List getChildren(){return null;}
? ? ?public void setChildren(List children){}
? ? ?public String getName() {return name;}
? ? ?public void setName(String name) {this.name = name;}
}
三 創(chuàng)建樹中的數(shù)據(jù)結(jié)構(gòu)
代碼如下
package example.my.treeview.data;
import java.util.ArrayList;
public class DataFactory {
? ? ?public static Object createTreeData(){
? ? ? ? ? ?//生成人的數(shù)據(jù)對(duì)象
? ? ? ? ? ?PeopleEntity p1 = new PeopleEntity("李紅霞");
? ? ? ? ? ?PeopleEntity p2 = new PeopleEntity("金利軍");
? ? ? ? ? ?PeopleEntity p3 = new PeopleEntity("何濤");
? ? ? ? ? ?//生成城市的數(shù)據(jù)對(duì)象
? ? ? ? ? ?CityEntity city1=new CityEntity("湖北");
? ? ? ? ? ?CityEntity city2=new CityEntity("北京");
? ? ? ? ? ?CityEntity city3=new CityEntity("湖南");
? ? ? ? ? ?//生成國家的數(shù)據(jù)對(duì)象
? ? ? ? ? ?CountryEntity c1 = new CountryEntity("美國");
? ? ? ? ? ?CountryEntity c2 = new CountryEntity("中國");
? ? ? ? ? ?//將數(shù)據(jù)對(duì)象連接起來
? ? ? ? ? ?//人和城市的關(guān)系
? ? ? ? ? ?{
? ? ? ? ? ? ? ? ?ArrayList list = new ArrayList();
? ? ? ? ? ? ? ? ?list.add(p1);
? ? ? ? ? ? ? ? ?city1.setChildren(list);
? ? ? ? ? ?}
? ? ? ? ? ?{
? ? ? ? ? ? ? ? ?ArrayList list = new ArrayList();
? ? ? ? ? ? ? ? ?list.add(p2);
? ? ? ? ? ? ? ? ?city2.setChildren(list);
? ? ? ? ? ?}
? ? ? ? ? ?{
? ? ? ? ? ? ? ? ?ArrayList list = new ArrayList();
? ? ? ? ? ? ? ? ?list.add(p3);
? ? ? ? ? ? ? ? ?city3.setChildren(list);
? ? ? ? ? ?}
? ? ? ? ? ?//城市和國家的關(guān)系
? ? ? ? ? ?{
? ? ? ? ? ? ? ? ?ArrayList list = new ArrayList();
? ? ? ? ? ? ? ? ?list.add(city1);
? ? ? ? ? ? ? ? ?c1.setChildren(list);
? ? ? ? ? ?}
? ? ? ? ? ?{
? ? ? ? ? ? ? ? ?ArrayList list = new ArrayList();
? ? ? ? ? ? ? ? ?list.add(city2);
? ? ? ? ? ? ? ? ?list.add(city3);
? ? ? ? ? ? ? ? ?c2.setChildren(list);
? ? ? ? ? ?}
? ? ? ? ? ?//將國家置于一個(gè)對(duì)象之下,
//這個(gè)對(duì)象可以是List也可以是數(shù)組
? ? ? ? ? ?{
? ? ? ? ? ? ? ? ?ArrayList list = new ArrayList();
? ? ? ? ? ? ? ? ?list.add(c1);
? ? ? ? ? ? ? ? ?list.add(c2);
? ? ? ? ? ? ? ? ?return list;
? ? ? ? ? ?}
? ? ?}
}
四 標(biāo)簽器和內(nèi)容器
TreeViewer和TableViewer一樣,是用內(nèi)容器和標(biāo)簽器來控制記錄對(duì)象的顯示,并且使用內(nèi)容器和標(biāo)簽器的語句也是一樣的。
下面是標(biāo)簽器的代碼
package example.my.treeview.internal;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.swt.graphics.Image;
/**
* @author hopeshared
* 標(biāo)簽提供器,控制紀(jì)錄在樹中顯示的文字和圖像等
*/
public class TreeViewerLabelProvider
implements ILabelProvider{
? ? ?//紀(jì)錄顯示 的文字,不能返回null
? ? ?public String getText(Object element){
? ? ? ? ? ?ITreeEntry entry = (ITreeEntry)element;
? ? ? ? ? ?return entry.getName();
? ? ?}
? ? ?//紀(jì)錄顯示的圖像
? ? ?public Image getImage(Object element){
? ? ? ? ? ?return null;
? ? ?}
? ? ?//以下方法暫不用,空實(shí)現(xiàn)
? ? ?public void addListener(ILabelProviderListener listener){}
? ? ?public void dispose(){}
? ? ?public boolean isLabelProperty(Object e, String p){return false;}
? ? ?public void removeListener(ILabelProviderListener listen){}
}
下面是內(nèi)容器的代碼
package example.my.treeview.internal;
import java.util.List;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
/**
* @author hopeshared
* 內(nèi)容器,由它決定哪些對(duì)象應(yīng)該輸出在TreeViewer里顯示
*/
public class TreeViewerContentProvider
implements ITreeContentProvider{
? ? ?//由這種方法決定樹的哪一級(jí)顯示哪些對(duì)象
? ? ?public Object[] getElements(Object inputElement)
? ? ?{
? ? ? ? ? ?if(inputElement instanceof List){
? ? ? ? ? ? ? ? ?List list = (List)inputElement;
? ? ? ? ? ? ? ? ?return list.toArray();
? ? ? ? ? ?}else{
? ? ? ? ? ? ? ? ?return new Object[0];//生成一個(gè)空的數(shù)組
? ? ? ? ? ?}
? ? ?}
? ? ?//判斷某節(jié)點(diǎn)是否有子節(jié)點(diǎn),如果有子節(jié)點(diǎn),
//這時(shí)節(jié)點(diǎn)前都有一個(gè)“+”號(hào)圖標(biāo)
? ? ?public boolean hasChildren(Object element){
? ? ? ? ? ?ITreeEntry entry = (ITreeEntry)element;
? ? ? ? ? ?List list = entry.getChildren();
? ? ? ? ? ?if(list==null||list.isEmpty()){return false;
? ? ? ? ? ?}else{return true;}
? ? ?}
? ? ?//由這個(gè)方法來決定父節(jié)點(diǎn)應(yīng)該顯示哪些子節(jié)點(diǎn)
? ? ?public Object[] getChildren(Object parentElement){
? ? ? ? ? ?ITreeEntry entry = (ITreeEntry)parentElement;
? ? ? ? ? ?List list = entry.getChildren();
? ? ? ? ? ?if(list==null || list.isEmpty()){return new Object[0];
? ? ? ? ? ?}else{return list.toArray();} ? ? ? ? ? ?
? ? ?}
? ? ?//以下方法空實(shí)現(xiàn)
? ? ?public Object getParent(Object element){return null;}
? ? ?public void dispose(){}
? ? ?public void inputChanged(Viewer v, Object oldInput, Object newInput){}
}
五 修改清單文件
下面給出的是plugin.xml文件代碼
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
<plugin>
? <extension point="org.eclipse.ui.views">
? ? <view
? ? class="example.my.treeview.internal.TreeViewPart"
id="example.my.treeview.treeview"
name="my first tree view plugin"/>
? </extension>
</plugin>
六 插件的實(shí)現(xiàn)
在清單文件中已經(jīng)指出了這個(gè)視圖的實(shí)現(xiàn)類是example.my.treeview.internal.TreeViewPart,下面給出這個(gè)文件的代碼
package example.my.treeview.internal;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
import example.my.treeview.data.DataFactory;
public class TreeViewPart extends ViewPart{
? ? ?public void createPartControl(Composite parent){
? ? ? ? ? ?Composite topComp = new Composite(parent, SWT.NONE);
? ? ? ? ? ?topComp.setLayout(new FillLayout());
? ? ? ? ? ?TreeViewer tv = new TreeViewer(topComp, SWT.BORDER);
? ? ? ? ? ?tv.setContentProvider(new TreeViewerContentProvider());
? ? ? ? ? ?tv.setLabelProvider(new TreeViewerLabelProvider());
? ? ? ? ? ?Object inputObj = DataFactory.createTreeData();
? ? ? ? ? ?tv.setInput(inputObj);
? ? ?}
? ? ?public void setFocus(){}
}
七 運(yùn)行結(jié)果
<抱歉,圖片上傳失敗>
八 給節(jié)點(diǎn)增加動(dòng)作
增加一個(gè)ActionGroup類
package example.my.treeview.internal;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.actions.ActionGroup;
/**
* @author hopeshared
* 生成菜單Menu,并將兩個(gè)Action傳入
*/
public class MyActionGroup extends ActionGroup{
? ? ?private TreeViewer tv;
? ? ?public MyActionGroup(TreeViewer treeViewer){
? ? ? ? ? ?this.tv = treeViewer;
? ? ?}
? ? ?//生成菜單Menu,并將兩個(gè)Action傳入
? ? ?public void fillContextMenu(IMenuManager mgr){
? ? ? ? ? ?//加入兩個(gè)Action對(duì)象到菜單管理器
? ? ? ? ? ?MenuManager menuManager = (MenuManager)mgr;
? ? ? ? ? ?menuManager.add(new OpenAction());
? ? ? ? ? ?menuManager.add(new RefreshAction());
? ? ? ? ? ?//生成Menu并掛在樹Tree上
? ? ? ? ? ?Tree tree = tv.getTree();
? ? ? ? ? ?Menu menu = menuManager.createContextMenu(tree);
? ? ? ? ? ?tree.setMenu(menu);
? ? ?}
? ? ?//打開Action類
? ? ?private class OpenAction extends Action{
? ? ? ? ? ?public OpenAction(){
? ? ? ? ? ? ? ? ?setText("打開");
? ? ? ? ? ?}
? ? ? ? ? ?//繼承自Action的方法,動(dòng)作代碼寫在此方法中
? ? ? ? ? ?public void run(){
? ? ? ? ? ? ? ? ?IStructuredSelection selection = (IStructuredSelection)tv.getSelection();
? ? ? ? ? ? ? ? ?ITreeEntry obj = (ITreeEntry)(selection.getFirstElement());
? ? ? ? ? ? ? ? ?if(obj != null){
? ? ? ? ? ? ? ? ? ? ? ?MessageDialog.openInformation(null, null, obj.getName());
? ? ? ? ? ? ? ? ?}
? ? ? ? ? ?}
? ? ?}
? ? ?//刷新的Action類
? ? ?private class RefreshAction extends Action{
? ? ? ? ? ?public RefreshAction(){
? ? ? ? ? ? ? ? ?setText("刷新");
? ? ? ? ? ?}
? ? ? ? ? ?//繼承自Action的方法,動(dòng)作代碼寫在此方法中
? ? ? ? ? ?public void run(){
? ? ? ? ? ? ? ? ?tv.refresh();
? ? ? ? ? ?}
? ? ?}
}
接著,修改TreeViewPart.java,代碼如下
……
Object inputObj = DataFactory.createTreeData();
? ? ? ? ? ?//-------------加入動(dòng)作開始
? ? ? ? ? ?MyActionGroup actionGroup = new MyActionGroup(tv);
? ? ? ? ? ?actionGroup.fillContextMenu(new MenuManager());
? ? ? ? ? ?//-------------加入動(dòng)作結(jié)束
? ? ? ? ? ?tv.setInput(inputObj);
……
結(jié)果如下圖所示
<抱歉,圖片上傳不成功>
九 自定義擴(kuò)展點(diǎn)
我們想將這個(gè)視圖的顯示內(nèi)容與視圖框架分開,這樣,我們需要修改視圖顯示內(nèi)容的時(shí)候只要重新貢獻(xiàn)一次顯示內(nèi)容就可以了。
9.1 添加shema文件
這個(gè)sheme文件是采用可視化編輯器進(jìn)行編輯,然后pde自動(dòng)生成的,代碼如下
<?xml version='1.0' encoding='UTF-8'?>
<!-- Schema file written by PDE -->
<schema targetNamespace="example.my.treeview">
<annotation>
? ? <appInfo>
? ? ? <meta.schema plugin="example.my.treeview" id="datafactory" name="Data Factory"/>
? ? </appInfo>
? ? <documentation>
? ? ? [Enter description of this extension point.]
? ? </documentation>
? </annotation>
<element name="extension">
? ? <complexType>
? ? ? <sequence><element ref="factory"/></sequence>
? ? ? <attribute name="point" type="string" use="required">
? ? ? ? <annotation><documentation></documentation></annotation></attribute>
? ? ? <attribute name="id" type="string">
? ? ? ? <annotation><documentation></documentation></annotation></attribute>
? ? ? <attribute name="name" type="string">
? ? ? ? <annotation><documentation></documentation>
? ? ? ? ? <appInfo><meta.attribute translatable="true"/></appInfo></annotation>
? ? ? </attribute>
? ? </complexType>
? </element>
? <element name="factory">
? ? <complexType>
? ? ? <attribute name="id" type="string">
? ? ? ? <annotation><documentation></documentation></annotation></attribute>
? ? ? <attribute name="name" type="string">
? ? ? ? <annotation><documentation></documentation></annotation></attribute>
? ? ? <attribute name="class" type="string" use="required">
? ? ? ? <annotation><documentation></documentation></annotation></attribute>
? ? </complexType>
? </element>
? <annotation>
? ? <appInfo><meta.section type="since"/></appInfo>
<documentation>[Enter the first release in which this extension point appears.]
</documentation>
? </annotation>
? <annotation>
? ? <appInfo><meta.section type="examples"/></appInfo>
? ? <documentation>[Enter extension point usage example here.]</documentation>
? </annotation>
? <annotation>
? ? <appInfo><meta.section type="apiInfo"/></appInfo>
? ? <documentation>[Enter API information here.]</documentation></annotation>
? <annotation>
? ? <appInfo><meta.section type="implementation"/></appInfo>
<documentation>
[Enter information about supplied implementation of this extension point.]
? ? </documentation></annotation>
? <annotation>
? ? <appInfo><meta.section type="copyright"/></appInfo>
? ? <documentation></documentation></annotation>
</schema>
9.2 創(chuàng)建接口文件
ItreeEntry.java之前就已經(jīng)創(chuàng)建好了,不需要修改?,F(xiàn)在添加另一個(gè)接口文件,代碼如下:
package example.my.treeview.internal;
public interface IDataFactory {
? ? ?public Object createTreeData();
}
于是我們修改DataFactory.java,使它實(shí)現(xiàn)這個(gè)接口。
9.3 修改清單文件
我們來修改清單文件,加入擴(kuò)展點(diǎn)聲明,并擴(kuò)展它,代碼如下
……
<extension-point id="datafactory" name="Data Factory"
schema="schema/datafactory.exsd"/>
<extension point="example.my.treeview.datafactory">
<factoryclass="example.my.treeview.data.DataFactory"/>
</extension>
……
9.4 修改TreeviewPlugin.java
增加一個(gè)方法Object loadDataFactory(),代碼如下
……
public static Object loadDataFactory(){
? ? ? ?IPluginRegistry r=Platform. getPluginRegistry();
? ? ? ?String pluginID="example.my.treeview";
? ? ? ?String extensionPointID="datafactory";
? ? ? ?IExtensionPoint p=r.getExtensionPoint( pluginID, extensionPointID);
? ? ? ?IConfigurationElement[] c=p.getConfigurationElements();
? ? ? ?if( c != null) {
? ? ? ? ? ? ?for( int i= 0; i <c.length; i++) {
? ? ? ? ? ? ? ? ? ?IDataFactory data = null;
? ? ? ? ? ? ? ? ? ?try { data=( IDataFactory)c
.createExecutableExtension("class");
? ? ? ? ? ? ? ? ? ? ? ? ?if( data != null){ return data.createTreeData(); }
? ? ? ? ? ? ? ? ? ?} catch( CoreException x) { }}}
? ? ? ?return new Object();
? }
……
9.5 修改TreeViewPart.java
將
Object inputObj = DataFactory.createTreeData();
替換為
Object inputObj = TreeviewPlugin.loadDataFactory();
9.6 其他輔助文件
其實(shí)TreeViewerLabelProvider.java和TreeViewerContentProvider.java可以看成是對(duì)DataFactory這個(gè)擴(kuò)展點(diǎn)的輔助文件
9.7運(yùn)行
跟之前的實(shí)現(xiàn)沒有區(qū)別,但是我們向eclipse貢獻(xiàn)了一個(gè)擴(kuò)展點(diǎn)
十 參考資料
《Eclipse入門到精通》
www.sohozu.com
《自己動(dòng)手編寫Eclipse擴(kuò)展點(diǎn)》
EclipseCon2005_Tutorial1.pdf 《Contributing to Eclipse: Understanding and WritingPlug- ins》
圖片:

?
圖片:

?
經(jīng)過一個(gè)多小時(shí)的努力。。。(嘿嘿,以前沒有仔細(xì)研究Property什么的,今天弄了一下)
終于出現(xiàn)了property并且可以修改屬性頁中的值

代碼
example.my.treeview.rar哦,補(bǔ)充一下,由于模型(就是treeviewer中的初始數(shù)據(jù))是寫死的,改的property其實(shí)是修改了內(nèi)存中的對(duì)象的值。假如用emf做模型持久化,就會(huì)保存修改。但是目前是不能保存修改的。關(guān)于本文的討論還是很多的,也有很多有用的信息。見
http://www.eclipseworld.org/bbs/read.php?tid=168本文第一次發(fā)表是在社區(qū)之中,本來也沒覺得有轉(zhuǎn)到blog的必要,但是后來發(fā)覺自己的記憶力越來越差,曾經(jīng)作過的都忘記的差不多了,為了避免丟失,還是存在這里備份比較好。