RCP界面美化技術(轉)


Eclipse RCP 界面概覽

Eclipse RCP 簡介

Eclipse 是一種基於 Java 的可擴展開源開發平台。就其自身而言,它只是一個框架和一組服務,用於通過插件組件構建開發環境。同時也是提供了一套完善機制的 Rcp 平台。Eclipse 平台具有一組功能強大的插件(參見圖 1),這些插件可支持多種項目,比如 JDT 和 PDE。


圖 1.Eclipse 平台體系結構簡化圖
圖 1.Eclipse 平台體系結構簡化圖

圖中粉紅色的部分代表的是 Eclipse 的富客戶部平台(Rich Client Platform,RCP)的核心組件。圖中淡藍色所標示的部分代表的是可包含到基於 RCP 的應用程序中的可選(但建議包含)部件。而灰色部分所示的部件是可選內容。當使用 Eclipse 操作開發企業應用,應使用到以下內容:

運行庫 :

運行庫是基於 OSGi 規范用來定義 Eclipse 插件模型以及擴展概念和擴展點的代碼。運行庫還提供了一些額外服務,比如日志和並發性。

JFace/SWT :

標准小部件工具箱(Standard Widget Toolkit,SWT)是一組小部件集,為 Eclipse 提供了其外在感觀。JFace 是位於 SWT 之上的一層,提供了一些 模型 - 視圖 - 控制器(Model-View-Controller,MVC)類,以使開發圖形應用程序更為簡單。

工作台 :

工作台為 Eclipse 賦予了個性化。視圖、透視圖的概念以及編輯器等都在這一層定義。

幫助(用戶協助):

Eclipse 組件讓您可以為用戶提供協助。這可以通過幫助系統實現,該系統允許用戶搜索幫助文檔,也可以采用備忘單(cheatsheet),它可視為面向終端用戶的互動性任務列表。

更新 :

Eclipse 的更新組件提供了可允許您將應用程序從一個版本更新到另一個版本的設施。

RCP 程序界面區域划分

啟動 Eclipse,選擇默認的工作空間后,彈出的整個窗口稱為 Workbench(工作台),其主要由以下幾個部分組成:主菜單、工具條、透視圖、狀態欄。透視圖主要由編輯器和視圖組成。主要區域划分如下圖。


圖 2. 界面區域划分(Eclipse IDE 界面)
圖 2. 界面區域划分(Eclipse IDE 界面)

真實的企業應用項目應構建於 Workbench 之上的,典型的程序界面如下。


圖 3 界面區域划分(典型 RCP 業務界面)
圖 3 界面區域划分(典型 RCP 業務界面)

可以看出不加修飾的 RCP 程序整體風格朴素、顏色單調,本文通過對界面的美化可以達到如下效果。


圖 4 界面美化效果圖
圖 4 界面美化效果圖

Rcp 程序主體區域風格的美化

本章以示例的方式對程序的主體區域進行美化,美化的主要區域包括:菜單區域、工具欄區域、Editorarea 區域、狀態欄區域、進度條區域。

創建 RCP 程序示例

首先新建 RCP 的項目,在 eclipse 中新建 RCP 項目非常簡單。啟動 Eclipse,打開菜單 File->New->Project,選中 Plug-in Project 並且鍵入工程名。如:rcp.demo。在下一頁中,填寫此插件的基本屬性信息,對於問題 "Would you liketo create a rich client application?" 選擇 Yes。最后,使用所提供的模板 "Hello RCP" 並接受缺省設置來創建一個 RCP 的工程。生成的項目如下。


圖 5. 默認生成的 Hello RCP 項目
圖 5. 默認生成的 Hello RCP 項目

程序運行后展示的是一個簡單的 Workbench 窗口,通過修改 ApplicationWorkbenchWindowAdvisor 類中的 preWindowOpen() 方法將界面主要區域顯示出來。


清單 1. 控制界面區域顯示代碼片段

				
 public void preWindowOpen() { 
 IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); 
 configurer.setInitialSize(new Point(400, 300)); 
 // 顯示工具條區域
 configurer.setShowCoolBar(true); 
 // 顯示狀態欄區域
 configurer.setShowStatusLine(true); 
 // 顯示菜單區域
 configurer.setShowMenuBar(true); 
 // 顯示進度條區域
 configurer.setShowProgressIndicator(true); 
 configurer.setTitle("Hello RCP"); 
 } 

 

然后運行程序可以看到如下效果。


圖 6. 簡單的 Hello RCP 窗口
圖 6. 簡單的 Hello RCP 窗口

以圖書管理為例增加一個圖書管理的菜單和圖書入庫子菜單以及一個圖書入庫的工具欄按鈕。在 ApplicationActionBarAdvisor 類中修改 fillMenuBar 和 fillCoolBar 方法。代碼片段如下。


清單 2. 添加菜單和一個工具欄按鈕代碼片段

				
 protected void fillCoolBar(ICoolBarManager coolBar) { 
 ToolBarManager toorbar = new ToolBarManager(); 
 coolBar.add(toorbar); 
 BookInputAction aciton = new BookInputAction(); 
 aciton.setImageDescriptor(Activator 
 .getImageDescriptor("icons/bookInput.gif")); 
 // 添加一個工具欄按鈕
 toorbar.add(aciton); 
 } 

 protected void fillMenuBar(IMenuManager menuBar) { 
 MenuManager bookManage = new MenuManager("圖書管理"); 
 BookInputAction aciton = new BookInputAction(); 
 bookManage.add(aciton); 
 // 添加一個菜單
 menuBar.add(bookManage); 

 } 

 

菜單區域的美化

獲取系統默認生成的菜單區域后,對菜單進行美化。注意到 Menu 類提供公開的設置背景和字體的方法。只是提供了以下包可見的方法。setBackground、setBackgroundImage、 setForeground。通過反射調用這些方法對菜單進行設置。給控件添加背景是盡量用圖片,原因是圖片更加美觀,如果只是通過設置背景色改變背景那 樣有時過於單調。在 ApplicationWorkbenchWindowAdvisor 類中添加以下方法。


清單 3. 設置菜單背景圖片代碼片段

				
 public void setMenuBG(Image mimage) { 
 // 獲取 RCP 框架默認生成的菜單區域對象
 org.eclipse.jface.action.MenuManager mm = (MenuManager) ApplicationActionBarAdvisor 
 getDefault().getMenubar(); 
 Menu menu = mm.getMenu(); 
 // 通過反射給菜單區域添加圖片
 invoke("setBackgroundImage", menu, new Class[] { Image.class }, 
 new Image[] { mimage }); 
 } 
 Object invoke(String methodName, Object object, Class<?>[] argsTypes, 
 Object[] args) { 
 Object result = null; 
 try { 
 Method m = object.getClass().getDeclaredMethod(methodName, 
 argsTypes); 
 m.setAccessible(true); 
 result = m.invoke(object, args); 
 } catch (Exception e) { 
 e.printStackTrace(); 
 } 
 return result; 
 } 

 

然后在 ApplicationWorkbenchWindowAdvisor 類 postWindowOpen() 方法中調用一下 setMenuBG(Image mimage) 方法給菜單設置一個背景圖片。接下來修改菜單的字體,Menu 中沒有相關的設置菜單字體的方法。通過 SWT 提供的 OS 類調用 Windows 的 API 可以修改操作系統的菜單。在 ApplicationWorkbenchWindowAdvisor 類中添加如下方法和字段,代碼如下。


清單 4. 修改菜單字體代碼片段

				
 /** 
給操作系統菜單設置字體
 */ 
 public static void setSystemMenuFont(Font menuFont) { 
 if (menuFont != null){ 
 cur_info.cbSize = NONCLIENTMETRICSW.sizeof; 
 if (OS.SystemParametersInfo(OS.SPI_GETNONCLIENTMETRICS, 0, 
 cur_info, 0)) { 
 System.out.println("Font:=>"
 + new String(cur_info.lfMenuFont.lfFaceName)); 
 } 
 LOGFONTW fw = (LOGFONTW) menuFont.getFontData()[0].data; 
 cur_info.lfMenuFont.lfFaceName = fw.lfFaceName; 
 cur_info.lfMenuFont.lfHeight = fw.lfHeight; 
 cur_info.lfMenuFont.lfWidth = cur_info.lfMenuFont.lfWidth; 
 cur_info.lfMenuFont.lfEscapement = fw.lfEscapement; 
 cur_info.lfMenuFont.lfOrientation = fw.lfOrientation; 
 cur_info.lfMenuFont.lfWeight = fw.lfWeight; 
 cur_info.lfMenuFont.lfItalic = fw.lfItalic; 
 cur_info.lfMenuFont.lfUnderline = fw.lfUnderline; 
 cur_info.lfMenuFont.lfStrikeOut = fw.lfStrikeOut; 
 cur_info.lfMenuFont.lfCharSet = fw.lfCharSet; 
 cur_info.lfMenuFont.lfOutPrecision = fw.lfOutPrecision; 
 cur_info.lfMenuFont.lfClipPrecision = fw.lfClipPrecision; 
 cur_info.lfMenuFont.lfQuality = fw.lfQuality; 
 cur_info.lfMenuFont.lfPitchAndFamily = fw.lfPitchAndFamily; 
 cur_info.iMenuHeight = fw.lfHeight; 
 if (OS.SystemParametersInfo(42, 0, cur_info, 0)) { 
 System.out.println("iMenuHeight:=>" + cur_info.iMenuHeight); 
 System.out.println("iMenuHeight:=>"
 + OS.GetSystemMetrics(OS.SM_CYMENU)); 
 // 發送消息修改操作系統的菜單字體
 OS.SendMessage(0xffff, OS.WM_SETTINGCHANGE, 0, 0); 
 } else { 
 System.out.println("iMenuHeight:=>" + cur_info.iMenuHeight); 
 System.out.println("iMenuHeight:=>"
 + OS.GetSystemMetrics(OS.SM_CYMENU)); 
 } 
 } 
 } 
 /** 
將操作系統的菜單設置為默認值
 */ 

 public static void clearSystemMenuFont() { 
 if (OS.SystemParametersInfo(OS.SPI_GETNONCLIENTMETRICS, 0, cur_info, 0)) { 
 System.out.println("test:=>"
 + new String(cur_info.lfMenuFont.lfFaceName)); 
 } 
 cur_info.lfMenuFont.lfFaceName = org_info.lfMenuFont.lfFaceName; 
 cur_info.lfMenuFont.lfHeight = org_info.lfMenuFont.lfHeight; 
 cur_info.lfMenuFont.lfWidth = cur_info.lfMenuFont.lfWidth; 
 cur_info.lfMenuFont.lfEscapement = org_info.lfMenuFont.lfEscapement; 
 cur_info.lfMenuFont.lfOrientation = org_info.lfMenuFont.lfOrientation; 
 cur_info.lfMenuFont.lfWeight = org_info.lfMenuFont.lfWeight; 
 cur_info.lfMenuFont.lfItalic = org_info.lfMenuFont.lfItalic; 
 cur_info.lfMenuFont.lfUnderline = org_info.lfMenuFont.lfUnderline; 
 cur_info.lfMenuFont.lfStrikeOut = org_info.lfMenuFont.lfStrikeOut; 
 cur_info.lfMenuFont.lfCharSet = org_info.lfMenuFont.lfCharSet; 
 cur_info.lfMenuFont.lfOutPrecision = org_info.lfMenuFont.lfOutPrecision; 
 cur_info.lfMenuFont.lfClipPrecision = org_info.lfMenuFont.lfClipPrecision; 
 cur_info.lfMenuFont.lfQuality = org_info.lfMenuFont.lfQuality; 
 cur_info.lfMenuFont.lfPitchAndFamily = org_info.lfMenuFont.lfPitchAndFamily; 
 cur_info.iMenuHeight = org_info.iMenuHeight; 
 if (OS.SystemParametersInfo(42, 0, cur_info, 0)) { 
 System.out.println("clear:=>" + cur_info.iMenuHeight); 
 OS.SendMessage(0xffff, OS.WM_SETTINGCHANGE, 0, 0); 
 } 
 } 

 

同樣在 ApplicationWorkbenchWindowAdvisor 類 postWindowOpen() 方法中調用一下 setSystemMenuFont(Font menuFont) 為菜單設置一種字體即可。這個方法的缺點是 RCP 程序運行時操作系統的所有菜單全改變了(個別機器系統環境的原因可能無效)。不要忘了在 Application 類中的 stop 方法中調用 clearSystemMenuFont() 方法在程序結束后將菜單樣式恢復到系統默認。在 postWindowOpen() 方法中重繪一下 Shell,調用 getWindowConfigurer().getWindow().getShell().redraw() 即可。

重新運行程序顯示效果如下。


圖 7. 菜單區域美化后的效果圖
圖 7. 菜單區域美化后的效果圖

工具欄區域的美化

和美化菜單的步驟一致,首先獲取 RCP 框架中生成的工具欄對象。並對其設置背景圖片。然后在 postWindowOpen() 方法中調用。


清單 5. 美化工具欄代碼片段

				
 public void setToorbarBG(Image timage) { 
 Object[] childrens = getWindowConfigurer().getWindow().getShell() 
 .getChildren(); 
 for (int i = 0; i < childrens.length; i++) { 
 String clazz = childrens[i].getClass().getName(); 
 // 獲取 RCP 框架默認生成的工具條對象
 if (clazz.endsWith("CBanner")) { 
 // 為工具欄設置圖片
 ((Composite) childrens[i]).setBackgroundImage(timage); 
 ((Composite) childrens[i]).setBackgroundMode(SWT.INHERIT_FORCE); 
 } 
 } 
 } 

 

程序運行后效果圖如下。


圖 8. 工具欄區域美化后的效果圖
圖 8. 工具欄區域美化后的效果圖

Editorarea 區域的美化

修改工作區域背景,使程序主體風格一致。首先獲取 RCP 框架中生成的 Editorarea 區域代表的對象。並對其設置背景圖片。最上面的 tabfolder 標簽區需要設置一下顏色。然后在 postWindowOpen() 方法中調用一下。


清單 6. 美化 Editorarea 區域代碼片段

				
 public void setEditorTabFolderColor(Color color) { 
 if (getWindowConfigurer().getWindow() == null) { 
 return; 
 } 
 if (getWindowConfigurer().getWindow().getActivePage() == null) { 
 return; 
 } 
 WorkbenchPage page = (WorkbenchPage) getWindowConfigurer().getWindow() 
 .getActivePage(); 
 Composite client = page.getClientComposite(); 
 Control[] children = client.getChildren(); 
 Composite child = (Composite) children[0]; 
 Control[] controls = child.getChildren(); 
 for (final Control control : controls) { 
 // 獲取 Editorarea 區域中的 tabfolder 對象
 if (control instanceof CTabFolder) { 
 control.setBackground(color); 
 } 
 } 
 } 
 public void setEditorAreaBG(Image image) { 
 if (getWindowConfigurer().getWindow() == null) { 
 return; 
 } 
 if (getWindowConfigurer().getWindow().getActivePage() == null) { 
 return; 
 } 
 WorkbenchPage page = (WorkbenchPage) getWindowConfigurer().getWindow() 
 .getActivePage(); 
 Composite client = page.getClientComposite(); 
 Control[] children = client.getChildren(); 
 Composite child = (Composite) children[0]; 
 Control[] controls = child.getChildren(); 
 for (final Control control : controls) { 
 if (control instanceof CTabFolder) { 
 CTabFolder tabfolder = (CTabFolder) control; 
 Listener[] listeners = tabfolder.getListeners(SWT.MenuDetect); 
 if (listeners != null) { 
 for (int i = 0; i < listeners.length; i++) { 
 // 屏蔽系統右鍵菜單
 tabfolder.removeListener(SWT.MenuDetect, listeners[i]); 
 } 
 } 
 Listener[] listeners2 = tabfolder.getListeners(SWT.DragDetect); 
 if (listeners2 != null) { 
 for (int i = 0; i < listeners2.length; i++) { 
 // 屏蔽編輯器默認可拖動的屬性
 tabfolder.removeListener(SWT.DragDetect, listeners2[i]); 
 } 
 } 
 tabfolder.setBackgroundImage(image); 
 tabfolder.setBackgroundMode(SWT.INHERIT_FORCE); 
 } 
 } 
 } 

 public void addPartListener(final Color color) { 
 getWindowConfigurer().getWindow().getActivePage().addPartListener( 
 new IPartListener() { 
 public void partActivated(IWorkbenchPart part) { 
 if (part instanceof EditorPart) { 
 setEditorTabFolderColor(color); 
 } 
 } 
 public void partBroughtToTop(IWorkbenchPart part) { 
 if (part instanceof EditorPart) { 
 setEditorTabFolderColor(color); 
 } 
 } 
 public void partClosed(IWorkbenchPart part) { 
 if (part instanceof EditorPart) { 
 setEditorTabFolderColor(color); 
 } 
 } 
 public void partDeactivated(IWorkbenchPart part) { 
 if (part instanceof EditorPart) { 
 setEditorTabFolderColor(color); 
 } 
 } 
 public void partOpened(IWorkbenchPart part) { 
 if (part instanceof EditorPart) { 
 setEditorTabFolderColor(color); 
 } 
 } 
 }); 
 } 
程序運行后效果圖如下。



圖 9. Editorarea 區域美化后的效果圖
圖 9. Editorarea 區域美化后的效果圖

狀態欄區域的美化

首先獲取 RCP 框架中生成的狀態欄區域代表的對象。並對其設置背景圖片。然后在 postWindowOpen() 方法中調用一下。


清單 7. 美化狀態欄區域代碼片段

				
 public void setStausLineBG(Image image) { 
 Object[] childrens = getWindowConfigurer().getWindow().getShell() 
 .getChildren(); 
 for (int i = 0; i < childrens.length; i++) { 
 String clazz = childrens[i].getClass().getName(); 
 // 獲取 RCP 框架默認生成的狀態欄區域對象
 if (clazz.endsWith("StatusLine")) { 
 ((Composite) childrens[i]).setBackgroundImage(image); 
 ((Composite) childrens[i]).setBackgroundMode(SWT.INHERIT_FORCE); 
 } 
 } 
 } 
程序運行后效果圖如下。



圖 10. 狀態欄區域美化后的效果圖
圖 10. 狀態欄區域美化后的效果圖

進度指示條區域的美化

首先獲取 RCP 框架中生成的進度指示條區域代表的對象。並對其設置背景圖片。然后在 postWindowOpen() 方法中調用一下。


清單 8. 進度指示條區域代碼片段

				
 public void setProgressIndicatorBG(Image image) { 
 Object[] childrens = getWindowConfigurer().getWindow().getShell() 
 .getChildren(); 
 for (int i = 0; i < childrens.length; i++) { 
 String clazz = childrens[i].getClass().getName(); 
 //RCP 框架默認生成的進度條區域對象
 if (clazz.endsWith("ProgressRegion$1")) { 
 ((Composite) childrens[i]).setBackgroundImage(image); 
 ((Composite) childrens[i]).setBackgroundMode(SWT.INHERIT_FORCE); 
 } 
 } 
 } 
程序運行后效果圖如下。



圖 11. 進度指示條區域美化后的效果圖
圖 11. 進度指示條區域美化后的效果圖

縫隙處是程序默認的顏色,影響了美觀。只要給背景的 Shell 設置一下顏色即可。在 postWindowOpen() 方法中加入一下代碼。

 getWindowConfigurer().getWindow().getShell().setBackground( 
 new Color(Display.getDefault(), 181, 220, 255)); 
 getWindowConfigurer().getWindow().getShell().setBackgroundMode( 
 SWT.INHERIT_FORCE); 
運行后效果圖如下。



圖 12. Shell 加背景顏色效果圖
圖 12. Shell 加背景顏色效果圖

界面控件的美化

本章節通過在 Hello RCP 示例的基礎上添加圖書管理錄入頁面展示界面的美化。在 SWT 中基本上所有的窗體控件都繼承了 Control 類。Control 中提供了 setBackground、setBackgroundImage、setFont、setForeground 等方法用於美化控件。

為 Composite 添加背景

首先我們創建一個簡單的圖書錄入頁面。然后需要將我們的頁面嵌入到 RCP 程序中的 Editorarea 區域中,新建一個 Editor,並將我們創建的頁面放入到 Editor 中。Editor 的相關代碼如下。


清單 9. Editor 代碼片段

				
 public class BookManageEditor extends EditorPart { 

 @Override 
 public void doSave(IProgressMonitor monitor) { 
 } 

 @Override 
 public void doSaveAs() { 
 } 

 @Override 
 public void init(IEditorSite site, IEditorInput input) 
 throws PartInitException { 
 setSite(site); 
 setInput(input); 
 } 

 @Override 
 public boolean isDirty() { 
 return false; 
 } 

 @Override 
 public boolean isSaveAsAllowed() { 
 return false; 
 } 

 @Override 
 /** 
 創建 editor 區域的頁面展示區域
 */ 
 public void createPartControl(Composite parent) { 
 InputComposite input = new InputComposite(parent, SWT.NONE); 
 } 

 @Override 
 public void setFocus() { 
 } 

 } 
接下來在圖書管理菜單下創建一個圖書管理的圖書錄入子菜單,添加一個操作。當點擊菜單時將打開我們的圖書錄入的頁面。操作 Action 的相關代碼如下。



清單 10. Action 代碼片段

				
 public class BookInputAction extends Action { 

 public BookInputAction() { 
 super(); 
 super.setText("圖書入庫"); 
 } 

 public void run() { 
 IWorkbench workbench = PlatformUI.getWorkbench(); 
 IWorkbenchWindow window = workbench.getActiveWorkbenchWindow(); 
 WorkbenchPage page = (WorkbenchPage) window.getActivePage(); 
 try { 
 // 通過 editor 的 id 號打開對應的 editor 
 page.openEditor(new BookManageEditorInput(), "rcp.demo.editor"); 
 } catch (PartInitException e) { 
 e.printStackTrace(); 
 } 
 } 

 class BookManageEditorInput implements IEditorInput { 

 public boolean exists() { 
 return false; 
 } 

 public ImageDescriptor getImageDescriptor() { 
 return null; 
 } 

 public String getName() { 
 return "圖書管理"; 
 } 

 public IPersistableElement getPersistable() { 
 return null; 
 } 

 public String getToolTipText() { 
 return "圖書管理"; 
 } 

 public Object getAdapter(Class adapter) { 
 return null; 
 } 
 } 

 } 

 

此時頁面背景是 SWT 默認的,通過調用 Composite 的 setBackgroundImage 方法為 Composite 添加背景圖片,之后調用一下 setBackgroundMode 讓在頁面上控件都繼承頁面的背景。


清單 11. 添加頁面背景代碼片段

				
 public InputComposite(Composite parent, int style) { 
   super(parent, style); 
   // 為頁面添加背景
   this.setBackgroundImage(Activator.getImageDescriptor( 
   "icons/content_blue.jpg").createImage()); 
   // 實現背景的繼承關系
   this.setBackgroundMode(SWT.INHERIT_FORCE); 
   ... 
   ... 
 } 
運行效果如下圖。



圖 13. 頁面效果圖
圖 13. 頁面效果圖

為頁面控件添加統一的背景顏色

為了方便管理頁面同一類型的控件的風格,我們創建一個工廠類,用於創建頁面的控件。我們需要創建控件時通過工廠類獲取,而不是每次通過調用控件的構造函數來創建。


清單 12. 控件工廠類代碼片段

				
 public class ControlFactory { 

 public static Font controlFont; 
 public static Color controlForeColor; 
 public static Color controlBGColor = new Color(Display.getDefault(), 255, 
 255, 255); 
 private ControlFactory() { 
 } 
 synchronized public static ControlFactory getDefault() { 
 if (instance == null) { 
 instance = new ControlFactory(); 
 } 
 return instance; 
 } 
 /** 
 創建 label 控件
 */ 
 public Label createLabel(Composite parent, int style) { 
 Label label = new Label(parent, style); 
 if (controlFont != null) { 
 label.setFont(controlFont); 
 } 
 if (controlForeColor != null) { 
 label.setForeground(controlForeColor); 
 } 
 if (controlBGColor != null) { 
 label.setBackground(controlBGColor); 
 } 
 return label; 
 } 
 /** 
 創建 text 控件
 */ 
 public Text createText(Composite parent, int style) { 
 Text text = new Text(parent, style); 
 if (controlFont != null) { 
 text.setFont(controlFont); 
 } 
 if (controlForeColor != null) { 
 text.setForeground(controlForeColor); 
 } 
 if (controlBGColor != null) { 
 text.setBackground(controlBGColor); 
 } 
 return text; 
 } 
 /** 
 創建 combo 控件
 */ 
 public Combo createCombo(Composite parent, int style) { 
 Combo combo = new Combo(parent, style); 
 if (controlFont != null) { 
 combo.setFont(controlFont); 
 } 
 if (controlForeColor != null) { 
 combo.setForeground(controlForeColor); 
 } 
 if (controlBGColor != null) { 
 combo.setBackground(controlBGColor); 
 } 
 return combo; 
 } 
 } 

 

通過工廠類創建好頁面控件后,運行 RCP 項目界面效果如下。


圖 14. 控件效果圖
圖 14. 控件效果圖

利用 GC 實現突出顯示

在實際的項目需求中,用戶錄入后往往要求對錄入不符合要求的控件進行標識。控件自身沒有提供這個功能,我們需要自己通過 GC 類在控件上畫線。在控件中需要通過 addPaintListener 的方法獲取一個 GC 對象,通過該對象進行線條繪制。代碼如下。


清單 13. GC 繪圖代碼片段

				
 text_5.addPaintListener(new PaintListener() { 

 public void paintControl(PaintEvent e) { 
 GC gc = e.gc; 
 gc.setLineWidth(3); 
 gc.setForeground(Display.getDefault().getSystemColor( 
 SWT.COLOR_RED)); 
 gc.drawRectangle(1, 1, text_5.getSize().x-25, text_5.getSize().y-8); 
 gc.dispose(); 

 } 
 }); 



圖 15. GC 效果圖
圖 15. GC 效果圖

利用首選項全局設置界面風格

對於企業應用程序,應提供系統設置功能,讓用戶選擇喜歡的外觀風格和自定義設置。使用 Eclipse 首先項,通過首選項記錄用戶的自定義設置。每次打開程序時,使用用戶所選設置而取代默認值,這樣可以很好的實現用戶對 RCP 程序整體風格的設置。

創建控件整體風格設置和皮膚設置的首選項

首先需要加一個首選項的擴展,名字為系統風格設置。相應的 plugin .xml 的擴展點片段如下。


清單 14. plugin.xml 的擴展點片段 1

				
 <extension 
 point="org.eclipse.ui.preferencePages"> 
 <page 
 class="rcp.demo.preferences.SystemPreferencePage"
 id="rcp.demo.preferences.SystemPreferencePage"
 name="Hello_RCP 系統設置"> 
 </page> 
 </extension> 

 

新添加一個控件設置的首先項 page。可以對控件的背景和字體進行配置。相應的 plugin .xml 的擴展點片段如下。


清單 15. plugin.xml 的擴展點片段 2

				
 <extension point="org.eclipse.ui.preferencePages"> 
 <page class="rcp.demo.preferences.SystemPreferencePage"
 id="rcp.demo.preferences.SystemPreferencePage"name="Hello_RCP 系統設置"> 
 </page> 
 <page category="rcp.demo.preferences.SystemPreferencePage"
 class="rcp.demo.preferences.ControlPage" id="rcp.demo.preferences.ControlPage"
 </page> 
 </extension> 

 

新添加一個皮膚設置的首先項 page。可以對皮膚進行配置。相應的 plugin .xml 的擴展點片段如下。


清單 16. plugin.xml 的擴展點片段 3

				
 <extension 
 point="org.eclipse.ui.preferencePages"> 
 <page 
 class="rcp.demo.preferences.SystemPreferencePage"
 id="rcp.demo.preferences.SystemPreferencePage"
 name="Hello_RCP 系統設置"> 
 </page> 
 <page 
 category="rcp.demo.preferences.SystemPreferencePage"
 class="rcp.demo.preferences.ControlPage"
 id="rcp.demo.preferences.ControlPage"
 name="控件設置"> 
 </page> 
 <page 
 category="rcp.demo.preferences.SystemPreferencePage"
 class="rcp.demo.preferences.SkinPage"
 id="rcp.demo.preferences.SkinPage"
 name="皮膚設置"> 
 </page> 
 </extension> 

 

所有的 page 相關源碼參見本文提供的示例源碼。

首選項對話框與菜單關聯

創建一個 Action 關聯到菜單上用於打開首選項對話框。


清單 17. 打開首選項對話框 Action 代碼片段

				
 public class OpenPreferencesDialogAction extends Action { 

 protected String[] ids = new String[] { "rcp.demo.preferences.ControlPage", 
 "rcp.demo.preferences.SkinPage" }; 

 public OpenPreferencesDialogAction(String[] ids) { 
 super(); 
 this.setText("系統設置"); 
 if (ids != null) { 
 this.ids = ids; 
 } 
 } 

 public void run() { 
 PreferenceDialog dialog; 
 // 打開 eclipse 中提供的首選項設置對話框
 dialog = PreferencesUtil.createPreferenceDialogOn(null, 
 "rcp.demo.preferences.SystemPreferencePage", ids, null); 

 dialog.getShell().setText("系統設置"); 

 if (dialog.open() == 0) { 
 MessageDialog confrim = new MessageDialog(Display.getDefault() 
 .getActiveShell(), "確認信息", null, 

 "需要重啟應用程序才能生效 !", MessageDialog.QUESTION, new String[] { 
 IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }, 
 0); 
 if (confrim.open() == 0) { 
 PlatformUI.getWorkbench().restart(); 
 } 
 } 
 } 
 } 



圖 16. 首選項對話框
圖 16. 首選項對話框

創建 LookAndFeel 類管理系統風格

為了統一管理系統的字體,顏色,皮膚的風格,創建一個 LookAndFeel 類給系統提供字體,顏色,圖片等。程序中菜單區域、工具欄區域、editorarea 區域、狀態欄區域、進度條區域的圖片和顏色,還包括頁面的背景色,控件的字體和顏色都由該類提供。用戶設置的風格屬性保存到本地文件后,通過 LookAndFeel 類讀取,並根據用戶的設置給系統提供不同的字體、顏色和圖片。LookAndFeel 類的相關代碼可以參見本文的示例程序。

Rcp 程序控件整體風格設置

修改上一章中創建的控件工廠類,在創建控件的方法內部,通過 LookAndFeel 類為控件提供字體和背景。創建 Text 控件的代碼片段舉例如下。


清單 18. 通過 LookAndFeel 管理控件風格代碼片段

				
 // 在構造函數中通過 LookAndFeel 獲取控件字體和背景信息
 private ControlFactory() { 
 controlFont = LookAndFeel.getDefault().getControlFont(); 
 controlForeColor = LookAndFeel.getDefault().getFontColor(); 
 controlBGColor = LookAndFeel.getDefault().getControlBGColor(); 
 labelBGColor = LookAndFeel.getDefault().getLabelBGColor(); 
 lableForeColor = LookAndFeel.getDefault().getFontColor(); 
 } 
 // 創建 Text 時為其設置背景和字體
 public Text createText(Composite parent, int style) { 
 Text text = new Text(parent, style); 
 if (controlFont != null) { 
 text.setFont(controlFont); 
 } 
 if (controlForeColor != null) { 
 text.setForeground(controlForeColor); 
 } 
 if (controlBGColor != null) { 
 text.setBackground(controlBGColor); 
 } else { 
 text.setBackground(Display.getDefault().getSystemColor( 
 SWT.COLOR_WHITE)); 
 } 
 return text; 
 } 

 

完成相關代碼后,可以通過首選項對控件風格進行設置。


圖 17. 控件風格設置圖
圖 17. 控件風格設置圖

程序重啟后讀取首選項數據,使用前文所述方法修改程序外觀,程序展示如下效果。


圖 18. 控件風格效果圖
圖 18. 控件風格效果圖

實現換膚

實現換膚就是為 RCP 程序主體區域提供多套不同的背景圖片,這些圖片通過 LookAndFeel 類獲取,該類根據用戶的選擇為程序主體區域提供不同的菜單。以菜單區域為例,代碼片段如下。


清單 19. 通過 LookAndFeel 提供菜單背景圖片代碼片段

				
 //LookAndFeel 類中該方法用於提供菜單區域背景圖片
 public Image getMenuImage() { 
 if (LookAndFeel.TYPE_BLUE.equals(LookAndFeel.CURRENT_TYPE)) { 
 return Activator.getImageDescriptor("icons/menu_blue.jpg") 
 .createImage(); 
 } else if (LookAndFeel.TYPE_PURPLE.equals(LookAndFeel.CURRENT_TYPE)) { 
 return Activator.getImageDescriptor("icons/menu_purple.jpg") 
 .createImage(); 
 } else { 
 return Activator.getImageDescriptor("icons/menu_blue.jpg") 
 .createImage(); 
 } 
 } 

 

完成相關代碼后,可以通過首選項對皮膚進行選擇。


圖 19. 皮膚設置圖
圖 19. 皮膚設置圖

程序提示重啟后,運行效果如下。


圖 20. 換膚效果圖
圖 20. 換膚效果圖

結束語

Eclipse 從某種意義上可以看作一個完善機制的 RCP 平台,由於其優秀的插件機制,近年來越來越多的被應用於企業應用項目。但由於開發人員更關注業務系統功能,而不注重程序美觀性,使 EclipseRCP 程序難以得到用戶的青睞。本文通過筆者在實際項目中的開發經驗,介紹了簡單的美化 Eclipse RCP 程序的方法,希望能對使用 Eclipse 平台的技術人員有所啟發。

 

原文地址:http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-rcprich/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM