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. 换肤效果图
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值