天天看點

給Eclipse插件的View加上菜單和工具條

Eclipse的每個視圖(View)都有自己的菜單和工具條,View通過與自己相關的IViewSite對象與這些東西打交道,确切的說,是通過這個IViewSite對象的IActionBars對象來管理,ActionBars對象負責菜單、工具條和狀态欄。

一個典型的View(繼承org.eclipse.ui.part.ViewPart)的代碼結構會是這樣,作為例子,假設我們有三個功能項:Open、Remove和Reload,我們的View是一個簡單的表格TableViewer,裡面顯示一些條目清單,允許使用者進行多選:

給Eclipse插件的View加上菜單和工具條

TableViewer tvResult;

給Eclipse插件的View加上菜單和工具條

OpenAction openAction;

給Eclipse插件的View加上菜單和工具條

RemoveAction removeAction;

給Eclipse插件的View加上菜單和工具條

ReloadAction reloadAction;

給Eclipse插件的View加上菜單和工具條

public void createPartControl(Composite parent) { 

給Eclipse插件的View加上菜單和工具條

    //建立視圖界面 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

    //建立菜單 

給Eclipse插件的View加上菜單和工具條

    createActions(); 

給Eclipse插件的View加上菜單和工具條

    createMenu(); 

給Eclipse插件的View加上菜單和工具條

    createContextMenu(); 

給Eclipse插件的View加上菜單和工具條

    createToolbar(); 

給Eclipse插件的View加上菜單和工具條

    hookGlobalActions(); 

給Eclipse插件的View加上菜單和工具條

給Eclipse插件的View加上菜單和工具條

其中,createActions()是建立必要的IAction對象,這些對象可用在菜單、工具條裡;createMenu()的作用是把剛剛建立的IAction對象放進與View相關的MenuManager裡,就像前面所說,MenuManager可以通過getViewSite().getActionBars().getMenuManager()方法得到;createToolbar()則是把同樣的對象放在工具條裡,獲得工具條的方法與菜單類似;createContextMenu()則是建立滑鼠右鍵觸發的上下文菜單,方法是建立一個新的MenuManager,然後由它建立一個Menu對象,再将Menu對象與控件聯系;hookGlobalActions()的作用是把IAction對象與系統菜單(而不是View菜單聯系),達到同一菜單項對不同View具有不同響應的效果。下面來看一下具體代碼:

給Eclipse插件的View加上菜單和工具條

package net.sf.solo.actions; 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

import java.io.IOException; 

給Eclipse插件的View加上菜單和工具條

import java.util.Iterator; 

給Eclipse插件的View加上菜單和工具條

import net.sf.solo.model.IInstance; 

給Eclipse插件的View加上菜單和工具條

import org.eclipse.jface.action.Action; 

給Eclipse插件的View加上菜單和工具條

import org.eclipse.jface.viewers.ISelectionChangedListener; 

給Eclipse插件的View加上菜單和工具條

import org.eclipse.jface.viewers.IStructuredSelection; 

給Eclipse插件的View加上菜單和工具條

import org.eclipse.jface.viewers.SelectionChangedEvent; 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

public class OpenAction extends Action implements ISelectionChangedListener { 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

    IStructuredSelection selection; 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

    public OpenAction() { 

給Eclipse插件的View加上菜單和工具條

        setEnabled(false); 

給Eclipse插件的View加上菜單和工具條

    } 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

    public void run() { 

給Eclipse插件的View加上菜單和工具條

        for (Iterator iter = selection.iterator(); iter.hasNext();) { 

給Eclipse插件的View加上菜單和工具條

            IInstance ins = (IInstance) iter.next(); 

給Eclipse插件的View加上菜單和工具條

            try { 

給Eclipse插件的View加上菜單和工具條

                //TODO Only in windows can do this. 

給Eclipse插件的View加上菜單和工具條

                Runtime.getRuntime().exec("cmd /E:ON /c start " + ins.getReferenceURL()); 

給Eclipse插件的View加上菜單和工具條

            } catch (IOException e) { 

給Eclipse插件的View加上菜單和工具條

                e.printStackTrace(); 

給Eclipse插件的View加上菜單和工具條

            } 

給Eclipse插件的View加上菜單和工具條

        } 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

    public void selectionChanged(SelectionChangedEvent event) { 

給Eclipse插件的View加上菜單和工具條

        selection = (IStructuredSelection) event.getSelection(); 

給Eclipse插件的View加上菜單和工具條

        setEnabled(selection.size() > 0); 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

    public String getText() { 

給Eclipse插件的View加上菜單和工具條

        return "&Open in browser"; 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

}

上面是一個例子IAction,它的作用是在觸發時将使用者選中的條目在浏覽器裡打開。這個類同時還實作了ISelectionChangeAction,這樣就可以在使用者沒有選中任何條目的時候将自己變為不可用。當然,你要把它作為監聽器加入某個清單對象的監聽器清單,像下面代碼裡這樣:

給Eclipse插件的View加上菜單和工具條

private void createActions() { 

給Eclipse插件的View加上菜單和工具條

    openAction = new OpenAction(); 

給Eclipse插件的View加上菜單和工具條

    removeAction = new RemoveAction(tvResult); 

給Eclipse插件的View加上菜單和工具條

    reloadAction = new ReloadAction(tvResult); 

給Eclipse插件的View加上菜單和工具條

    tvResult.addSelectionChangedListener(openAction); 

給Eclipse插件的View加上菜單和工具條

    tvResult.addSelectionChangedListener(removeAction); 

給Eclipse插件的View加上菜單和工具條

    tvResult.addSelectionChangedListener(reloadAction); 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

注意,最後的三句就是加入監聽清單的功能。有些IAction需要改變所監聽對象(比如一個TableViewer)的行為,是以要把那個對象作為參數傳遞給它才行。下面是把IAction對象加入菜單的代碼:

給Eclipse插件的View加上菜單和工具條

private void createMenu() { 

給Eclipse插件的View加上菜單和工具條

    IMenuManager mgr = getViewSite().getActionBars().getMenuManager(); 

給Eclipse插件的View加上菜單和工具條

    mgr.add(openAction); 

給Eclipse插件的View加上菜單和工具條

    mgr.add(removeAction); 

給Eclipse插件的View加上菜單和工具條

    mgr.add(reloadAction); 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

把IAction對象加到工具條的代碼幾乎完全一樣,隻是第一句有所不同:

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

    IToolBarManager mgr = getViewSite().getActionBars().getToolBarManager(); 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

上下文菜單就顯得有些麻煩了,因為View并沒有一個“PopupMenuManager”這樣的東西,是以我們隻能半手動的來建立:

給Eclipse插件的View加上菜單和工具條

private void createContextMenu() { 

給Eclipse插件的View加上菜單和工具條

    MenuManager mgr = new MenuManager(); 

給Eclipse插件的View加上菜單和工具條

    mgr.setRemoveAllWhenShown(true); 

給Eclipse插件的View加上菜單和工具條

    mgr.addMenuListener(new IMenuListener() { 

給Eclipse插件的View加上菜單和工具條

        public void menuAboutToShow(IMenuManager manager) { 

給Eclipse插件的View加上菜單和工具條

            fillContextMenu(manager); 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

    }); 

給Eclipse插件的View加上菜單和工具條

    Menu menu = mgr.createContextMenu(tvResult.getControl()); 

給Eclipse插件的View加上菜單和工具條

    tvResult.getControl().setMenu(menu); 

給Eclipse插件的View加上菜單和工具條

    getSite().registerContextMenu(mgr, tvResult); 

給Eclipse插件的View加上菜單和工具條

這個MenuManager和我們在createMenu()裡通過getMenuManager()得到的是同一個類(但不是同一個執行個體哦),setRemoveAllWhenShown(true)的作用是清空以前顯示的菜單項,當觸發了menu事件時,重新填充(fillContextMenu),是以如果你不把removeAllWhenShow置為true的話,每點一下右鍵你就會看到菜單項多出一倍來。Menu是swt的控件(剛才說的MenuManager、ToolbarManager都是jface裡的東西,jface給swt包了一層),用MenuManager可以建立出一個Menu對象,然後我們用表格的setMenu方法将表格控件與Menu控件聯系在一起就好了。

最後還有一句,它是為擴充這個上下文菜單用的,例如你可以在plugin.xml裡統一指定給某種類型的元素都加上某個菜單項(例如,如果使用者選中了一個.zip檔案,會多出一個“解壓縮”選項)。那麼新加的菜單項會出現在上下文菜單的哪裡呢,最上方還是最下方,還是……?是以呢,要在fillContextMenu的時候指定一下:

給Eclipse插件的View加上菜單和工具條

protected void fillContextMenu(IMenuManager manager) { 

給Eclipse插件的View加上菜單和工具條

    manager.add(openAction); 

給Eclipse插件的View加上菜單和工具條

    manager.add(removeAction); 

給Eclipse插件的View加上菜單和工具條

    manager.add(reloadAction); 

給Eclipse插件的View加上菜單和工具條

    manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS)); 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

前三句都沒什麼特别,最後一句就是指定了上面我們說的這個“增加點”,這樣,你想讓後來的菜單放在哪裡都行了。

最後,Eclipse的Workbench提供了一些比較通用的系統菜單項,如下:

給Eclipse插件的View加上菜單和工具條

public static final String [] GLOBAL_ACTIONS = { 

給Eclipse插件的View加上菜單和工具條

        UNDO, 

給Eclipse插件的View加上菜單和工具條

        REDO, 

給Eclipse插件的View加上菜單和工具條

        CUT, 

給Eclipse插件的View加上菜單和工具條

        COPY, 

給Eclipse插件的View加上菜單和工具條

        PASTE, 

給Eclipse插件的View加上菜單和工具條

        PRINT, 

給Eclipse插件的View加上菜單和工具條

     DELETE, 

給Eclipse插件的View加上菜單和工具條

        FIND, 

給Eclipse插件的View加上菜單和工具條

     SELECT_ALL, 

給Eclipse插件的View加上菜單和工具條

        BOOKMARK 

給Eclipse插件的View加上菜單和工具條

}; 

給Eclipse插件的View加上菜單和工具條

當你的焦點在不同的View或Editor裡時,同一個系統菜單項會有不同的作用産生。例如在文本編輯器中delete項是删除目前選中的文字,而在你的視圖裡,你希望delete的作用是删除使用者選中的表格條目,剛好是removeAction的功能。是以你要把你的IAction對象和系統菜單挂在一起:

給Eclipse插件的View加上菜單和工具條

private void hookGlobalActions() {

給Eclipse插件的View加上菜單和工具條

      IActionBars bars = getViewSite().getActionBars(); 

給Eclipse插件的View加上菜單和工具條

      bars.setGlobalActionHandler(IWorkbenchActionConstants.DELETE, removeAction); 

給Eclipse插件的View加上菜單和工具條
給Eclipse插件的View加上菜單和工具條

注意,要選擇語義上比較相近的系統菜單項來挂接,否則會造成使用者的困擾。比如你非要把COPY實作為openAction,當使用者在系統菜單裡選了copy指令,本以為會把目前選中的條目複制到剪貼闆,你卻給人家打開了這些條目,多滑稽。

好了,菜單方面基本上就這些内容。可以看出,Eclipse的Workbench的确為我們提供了很多友善,特别是如果能夠靈活利用plugin來進行定義,不僅可以節約大量的代碼,還能讓我們始終保持對系統的掌握。是以說,RCP的風行可不是沒有道理哦。

繼續閱讀