• 为 RCP 提供捷径的实用 Eclipse 系统类(转载)


    简介: Eclipse 提供了 RCP 应用开发的内核,本身已经提供了许多有用的类,熟悉并且使用这些类,不仅可以减少代码量的开发,还可以提高代码的健壮性。既然 RCP 运行于 Eclipse 内核之上,就应该尽量多的使用系统自带的类。如 SafeRunner 提供了异常记入日志的功能、BusyIndicator 可以屏蔽鼠标事件,使得当前程序专注于处理一件事,而不使程序出现死的状态,鼠标变为漏斗状。本文尽可能详细的介绍这些类,用示例代码展示它们的用法,相信读者可以从本文掌握它们的使用技巧。

    引言

    RCP(Rich Client Platform),即富客户端平台,是 Eclipse 提供给开发者的强大的开放性开发平台,允许开发基于 Eclipse 的应用程序,风格将与 Eclipse 相同。由于是基于 Eclipse,因此 Eclipse 中许多有用的系统类,就可以在开发者自己的 RCP 应用中利用起来,这样不仅减少了开发量,也大大提高了系统稳定性。本文介绍了一些笔者在实际开发中用到的 Eclipse 系统类,详细的认识它们可以为你的 RCP 开发提供捷径。


    实用类简介

    本文将逐一的介绍几个实用类,顺序如下面的列表。

    • SafeRunner 的用法
    • BusyIndicator 的用法
    • PreferencesUtil 的用法
    • IDialogSettings 的用法
    • FileLocator 的用法
    • WorkbenchHelp 的用法
    • MessageDialogWithToggle 的用法
    • 视图 ViewPart 中的 IMemento
    • 重新认识 Display 类

    列表的每一部分分别讲述一个实用类的具体用法,文章的附件中会有这些类使用的示例代码,每个实用类对应的使用示例代码以“类名” + UseCase.java 命名 。为了方便读者查看效果,附件程序中每个类的示例代码都有一个对应的按钮,读者可以点击对应的按钮查看效果,附件程序界面如图 1 所示。读者将附件导入 Eclipse 工作空间即可运行。


    图 1. 示例程序界面
    图 1. 示例程序界面


    SafeRunner 的用法

    在 Java 开发中,很多时候所写的语句可能抛出异常,这就需要程序员抒写 try … catch 语句,将异常语句包围,在 catch 语句块中对异常进行处理,在 RCP 应用中对意外抛出的异常一般都需要先记录到日志文件中,方便日后查询,然后根据需求进行别的处理。用传统的方法处理 RCP 中的异常,不仅仅要写 try … catch 语句,还需要编写记录 Eclipse 日志的代码,如果异常语句多了的话,代码就会显得臃肿,不易理解。

    Eclipse 提供了一个类,名为 SafeRunner,允许开发者将异常代码放入 SafeRunner 的 run 方法中执行,SafeRunner 默认对异常代码添加 try … catch 语句,捕捉异常并且将异常信息记录日志,同时 SafeRunner 也允许开发者对异常进行其他处理。SafeRunner 的使用方法如清单 1 所示。


    清单 1. SafeRunner 的使用

    				
     System.out.println("语句 1"); 
     SafeRunner.run(new ISafeRunnable() { 
          
          @Override 
          public void run() throws Exception { 
            // 异常代码的执行位置
            System.out.println("语句 2(可能抛出异常)"); 
            throw new RuntimeException("语句 2 的异常"); 
          } 
          
          @Override 
          public void handleException(Throwable exception) { 
            // 对异常进行其他处理
            exception.printStackTrace(); 
          } 
     }); 
     System.out.println("语句 3"); 
    


     

    在 handleException 方法中可以对异常进行其他的处理,比如打印异常信息、记录到数据库等等。

    当在 RCP 应用中执行清单 1 中的代码,它的日志文件就会记录抛出的异常,效果如图 2 所示。


    图 2. 使用 SafeRunner 的日志文件
    图 2. 使用 SafeRunner 的日志文件

    使用 SafeRunner 使得 RCP 的异常处理变得规范化,代码量减少,更易维护,无需自己编写日志记录代码。


    BusyIndicator 的用法

    当试图在执行一个线程任务的同时,主线程停止等待,直到任务执行完毕,这个需求开发者一般会想到使用 Display 的 sync 方法,将任务放入主线程执行,这样执行的缺点是,任务执行时主线程停止响应,给人程序已死的感觉。因此为了解决这个缺点,就可以使用 BusyIndicator 执行任务,它使得任务执行时鼠标显漏斗状,标识主线程忙碌,实际任务在另一线程执行。附件程序中点击”BusyIndicator”按钮就会展示 BusyIndicator 的使用效果,执行的代码如清单 3 所示。


    清单 2. BusyIndicator 的示例代码

    				
     public static void handleClick(Button button) { 
        button.setText("Running..."); 
    
        BusyIndicator.showWhile(button.getDisplay(), 
            new SleepThread(5000)); 
    
        button.setText("BusyIndicator"); 
      } 
    
      static class SleepThread extends Thread { 
        private long ms; 
    
        public SleepThread(long ms) { 
          this.ms = ms; 
        } 
    
        public void run() { 
          try { 
            sleep(ms); 
          } catch (InterruptedException e) { 
          } 
        } 
      } 
    


     

    用户点击”BusyIndicator”按钮,就改变”BusyIndicator”按钮的标签,改为 Running … , 执行的任务在 SleepThread 中,使用线程的 sleep 方法,模拟任务执行 5 秒。任务执行过程中,主程序虽然没有响应,但是不会有程序已死的感觉,鼠标显示漏斗状。执行任务后按钮的标签恢复成“BusyIndicator”, 鼠标箭头也恢复正常。


    PreferencesUtil 的用法

    Eclipse 提供了首选项扩展点,允许开发者定义自己的首选项集成到 Eclipse 当中(具体的首选项扩展点的扩展方法可以查看 Eclipse 官方开发文档),正常来说,用户可以通过 Eclipse 的 Window->Preferences 菜单打开所有的首选项,然后找到自定义的首选项页。但是如果开发者希望可以通过别的方式打开自定义的首选项页时,就需要利用到 PreferencesUtil,这个类提供了打开指定首选项页的功能,附件程序中定义了一个首选项,id 为 testPreferencesUtilPage,name 为 Test PreferencesUtil Page,清单 4 是使用 PreferencesUtil 打开 id 为 testPreferencesUtilPage 的首选页的方法代码。


    清单 3. PreferencesUtil 的示例代码

    				
     PreferenceDialog createPreferenceDialogOn = 
     PreferencesUtil.createPreferenceDialogOn(null, "testPreferencesUtilPage", null, null); 
     createPreferenceDialogOn.open(); 
    


     

    读者可以在附件程序中点击“PreferencesUtil”按钮查看效果,效果如图 3 所示。


    图 3. PreferencesUtil 的示例效果
    图 3. PreferencesUtil 的示例效果


    IDialogSettings 的用法

    IDialogSettings 是一个为对话框设置提供持久化功能的一个接口,该接口提供了键值对的存储机制,键必须是字符串,值则可以是字符串或者字符串数组(IDialogSettings 提供的方法允许值是非字符串类型,但是 IDialogSettings 的实现会将其他非字符串类型的基本类型转换为字符串类型,然后保存)。开发者希望在对话框关闭时候保存状态,打开对话框恢复状态时,就可以利用 IDialogSettings 接口了。附件程序使用 InputDialog,将用户输入的内容保存到 IDialogSettings 实例中,使用 IDialogSettings 的 save 方法将 IDialogSettings 中的信息保存到本地文件,在第二次打开 InputDialog 时,又使用 IDialogSettings 的 load 方法加载设置。代码如清单 5 所示。


    清单 4. IDialogSettings 的使用

    				
     private static IDialogSettings ds = new DialogSettings("myds"); 
      public static void handleClick() { 
        String fileName = "c:/save.xml"; 
        if (new File(fileName).exists()) 
        { 
          try { 
            ds.load(fileName); 
          } catch (IOException e1) { 
            e1.printStackTrace(); 
          } 
        } 
        InputDialog id = new InputDialog(null, "IDialogSettings Title", 
            "IDialogSettings Message", ds.get("iduc") == null ? "" : ds.get("iduc"), null); 
        if (id.open() == Window.OK) 
        { 
          ds.put("iduc", id.getValue()); 
        } 
        try { 
          ds.save(fileName); 
        } catch (IOException e) { 
          e.printStackTrace(); 
        } 
      } 
    


     

    在 InputDialog 中输入 helloworld, 点击 OK,打开清单 5 中保存的文件 c:/save.xml,它的内容如清单 6 所示。可以看出 IDialogSettings 中的信息通过调用 save 方法,保存成了一个 XML 文件格式。


    清单 5. save.xml 的内容

    				
     <?xml version="1.0" encoding="UTF-8"?> 
     <section name="myds"> 
      <item value="helloworld" key="iduc"/> 
     </section> 
    


     

    清单5中,IDialogSettings 的实例是自己新建,它的 save 和 load 操作需要开发人员自己控制,有时候为了方便,我们可以使用已经有的 IDialogSettings 实例,让平台负责它们的读写,如 JavaPlugin.getDefault().getDialogSettings() 就可以获得 JavaPlugin 中的 IDialogSettings 实例,加载保存都归 Java 插件管理。


    FileLocator 的用法

    在 Eclipse 中编辑项目时,往往会根据需要在项目中新建一些文件,如 properties 文件等等,当我们需要在 RCP 运行时找到这些文件时,就需要利用 FileLocator 类。为此,附件程序中新建一个 properties 文件(fileLocator.properties)在项目的根目录下,内容为 filelocator=FileLocatorUseCase,接下来利用 Filelocator 找到这个属性文件,读取该文件内容,使用 Java 的资源 API 获取键为 filelocator 的 FileLocatorUseCase 值,并弹出对话框显示,代码如清单 7 所示。


    清单 6. FileLocator 的使用

    				
        URL location = FileLocator.find(Platform 
            .getBundle("eclipse_system_class"), new Path( 
            "fileLocator.properties"), null); 
        PropertyResourceBundle bundle = null; 
        InputStream is = null; 
        String aboutText = ""; 
        if (location != null) { 
          try { 
            is = location.openStream(); 
            bundle = new PropertyResourceBundle(is); 
          } catch (IOException e) { 
            bundle = null; 
          } finally { 
            try { 
              if (is != null) 
                is.close(); 
            } catch (IOException e) { 
            } 
          } 
        } 
    
        if (bundle != null) { 
          try { 
            // 值
            aboutText = bundle.getString("filelocator"); 
            MessageDialog.openInformation(null, "FileLocator", aboutText); 
          } catch (MissingResourceException e) { 
          } 
        } 
    


     

    通过插件的 ID,使用 Platform 类的 getBundle 方法获取插件的 Bundle,FileLocator 的 find 方法相对 Bundle 的根目录寻找文件(fileLocator.properties),将获取的文件输入流封装成 PropertyResourceBundle,这样就可以根据键值 filelocator 获得 FileLocatorUseCase 值了。


    WorkbenchHelp 的用法

    在了解 WorkbenchHelp 之前,读者需要了解 Eclipse 中的帮助扩张点,这个扩张点的目的是为开发者提供自定义帮助内容的方法,该扩展点的具体使用方法可以查看 Eclipse 官方开发文档。WorkbenchHelp 类提供了快捷的 API,用以设置、显示、获得帮助扩展点的帮助。附件程序展示了如何为视图的 Composite 添加帮助,当焦点落在 Composite 时,按 F1 键,会显示定义好的帮助内容。或者点击“WorkbenchHelp”按钮,也会显示帮助内容。显示效果如图 4 所示。


    图 4. 使用 WorkbenchHelp 显示帮助
    图 4. 使用 WorkbenchHelp 显示帮助

    为视图 Composite 设置 F1 帮助的代码如清单 8 所示。


    清单 7. 设置 F1 显示帮助

    				
     public void createPartControl(Composite parent) 
     { 
      Composite com = new Composite(parent, SWT.NONE); 
      ... 
      WorkbenchHelp.setHelp(com, "eclipse_system_class.contexthelp"); 
     } 
    


     

    WorkbenchHelp 的 setHelp 方法为控件设置帮助,它的第二个参数值 eclipse_system_class.contexthel 中的 contexthelp,是附件程序扩展 org.eclipse.help.contexts 扩展点定义的 context 的 id,eclipse_system_class 则为附件程序的插件 ID,清单 8 利用 WorkbenchHelp 为 Composite 绑定了帮助,点击 F1 时显示 id 为 contexthelp 的帮助内容。当试图在其他事件(不是点击 F1)时显示帮助,WorkbenchHelp 提供了直接显示帮助的方法:WorkbenchHelp.displayHelp("eclipse_system_class.contexthelp"); 在任何事件监听器中调用 displayHelp 方法,都可以显示帮助内容。


    MessageDialogWithToggle 的用法

    MessageDialogWithToggle 是一个带有 CheckBox 的提示对话框,MessageDialogWithToggle 不仅保存了用户点击的按钮信息,还保存了用户是否选中了 ChekBox。MessageDialogWithToggle 在 Eclipse 中的使用例子很多,比如关闭 Eclipse 时,会弹出如图 5 的对话框。该对话框就是 MessageDialogWithToggle 的实例。


    图 5. 退出 Eclipse 时的提示对话框
    图 5. 退出 Eclipse 时的提示对话框

    MessageDialogWithToggle 对话框适用于一个对话框包含两个提示问题的情况下,它的使用代码如清单 9 所示。


    清单 8. MessageDialogWithToggle 的使用

    				
     MessageDialogWithToggle dialogWithToggle = new MessageDialogWithToggle(null, 
            "MessageDialogWithToggle Title", null, "MessageDialogWithToggle Message", 
            MessageDialog.QUESTION, new String[] { IDialogConstants.YES_LABEL, 
                IDialogConstants.NO_LABEL}, 0, "是否选中 toggle?", false); 
        if (dialogWithToggle.open() == IDialogConstants.YES_ID) 
        { 
          boolean toggleState = dialogWithToggle.getToggleState(); 
          MessageDialog.openInformation(null, 
          "MessageDialogWithToggle", "是否选中 toggle " + toggleState); 
        } 
    


     

    执行清单 9 的代码效果将如图 6 所示。


    图 6. MessageDialogWithToggle 的示例效果
    图 6. MessageDialogWithToggle 的示例效果


    视图 ViewPart 中的 IMemento

    Eclipse 的工作台 Workbench 被关闭的时候,会执行每个视图 (ViewPart) 的 saveState 方法,一个 IMemento 对象就会传入到 saveState 方法中,在 IMemento 对象中可以存储整型、字符串型、浮点型等数据,我们就可以将一些状态信息等存储到 IMemento 中,平台会将这些数据存储到 org.eclipse.ui metadata 目录下的 workbench.xml 文件中。下次打开视图时,平台还会从 workbench.xml 重新读取 IMemento 对象,并且传入视图的 init 方法。那么 init 方法就可以恢复上一次关闭前的状态了。

    为了实现上述保存状态再恢复状态的功能,需要重写视图(ViewPart)的 init 和 saveState 方法,类似代码如清单 10 所示。


    清单 9. init 与 saveState 的重写

    				
     public void init(IViewSite site, IMemento memento) throws PartInitException 
     { 
        super.init(site, memento); 
        if (memento != null){ 
          String initData = memento.getString("initdata"); 
          // 每一次打开都会获得这个 initData. 
        } 
     } 
    
     public void saveState(IMemento memento) 
     { 
        // 改变状态的话,就在关闭的时候存储到 IMemento 中
        if (memento != null){ 
          
          memento.putString("initdata", "IMemento init"); 
        } 
     } 
    


     

    另外,打开视图的时候先执行 init,再执行视图的 createPartControl 方法,也就是说 init 的执行在创建组件之前,因此可以保存 init 方法的 IMemento 对象参数的引用,在 createPartControl 方法里使用,获得 IMemento 中存放的信息,这样就可以恢复上一次关闭前一些组件的属性值等。


    重新认识 Display 类

    Display 在 RCP 中具有很重要的地位,它的两个方法 sync 和 async 是同步和异步方法,sync 是将代码块立刻放入主线程执行,async 是在主线程空闲的时候再放入主线程执行。这两个方法在非主线程中更新 UI 时被大量用到。

    Display 还有很多别的方法会被人忽略,但是了解这些方法或许在以后的开发中有很大的帮助,

    addFilter方法用于添加全局监听器,任何在 RCP 应用中发生的同类事件都会触发 addFilter 的监听器。addFilter的使用示例代码如清单 11 所示。


    清单 10. addFilter 使用示例

    				
     display.addFilter(SWT.MouseDown, new Listener() {   
                @Override  
                public void handleEvent(Event e)   
                {   
                    System.out.println("filter mouse  down");   
                }   
            }); 
    


     

    Display 提供了寻找控件的方法,叫 findWidget,用于通过句柄快速寻找控件,在控件非常复杂的情况下,可以通过记录控件的句柄号 (Control 的 handle 属性 ),调用 findWidget 方法,快速获得控件,示例代码如清单 12 所示。


    清单 11. findWidget 使用示例

    				
     Button displayBtn = … ; 
     Control d = (Control)display.findWidget(displayBtn.handle);   
     System.out.println(d == displayBtn); 
    


     

    Display 的 getFocusControl方法返回当前应用中获得焦点的 Control 对象。

    Display 的 timerExec方法用于在指定毫秒数结束以后执行一段代码,为 RCP 程序提供定时执行的功能,它的代码如清单 13 所示。


    清单 12. timerExec 使用示例

    				
     // 在 5 秒后执行 Runnable 代码
     display.timerExec(5000, new Runnable() {   
      
                @Override  
                public void run()   
                {   
                    System.out.println("timerExec");   
                }   
            });   
    


     

    Display 的 disposeExec方法是程序退出时候的钩子,在 Display 被销毁的时候触发执行,通过这个方法允许你在程序退出时做一些收尾工作,它的示例代码如清单 14 所示。


    清单 13. disposeExec 使用示例

    				
     display.disposeExec(new Runnable(){   
      
                @Override  
                public void run()   
                {   
                    System.out.println("disposeExec");   
                }   
                   
            });  
    


     


    小结

    本文介绍了几个 RCP 开发中可能被用到的实用类,对这些类进行了讲解和代码示例分析,通过文章的介绍,相信读者可以从中掌握这些类的使用方法,在未来的 RCP 开发中事半功倍。由于本人知识水平有限,文章中倘若有错误的地方,欢迎联系我批评指正。

    转载自:

    http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-rcpclass/

  • 相关阅读:
    4.结构化机器学习项目
    九、LaTex中的浮动体
    第二章 决策树
    菜鸟教程C++(一)
    12月月计划与周计划
    目标检测常见错误
    Tensorflow object detection API(1)---环境搭建与测试
    爬取今日头条街拍美图
    BS4库详解
    requests库详解
  • 原文地址:https://www.cnblogs.com/wuhenke/p/2360417.html
Copyright © 2020-2023  润新知