zoukankan      html  css  js  c++  java
  • 关于Eclipse开发插件(三)

    视图之间实现事件监听

    两个视图中的组件之间的互动,在开发插件的时候是经常碰到的问题.点击视图1列表的某项时,视图2的文本框显示相应的字符.

    第一种主动式:

    主动式就是在视图1的代码块中获取对视图2的对象的引用.然后将视图1中的对象主动的传给视图2.

    修改View1.java和View2.java

    Eclipse通过plugin.xml来加载插件和插件中的扩展点(如视图扩展点),所以可以在View1.java中由id标识来取得视图2对象.

    View1.java

     1 public class View1 extends ViewPart {
     2     private List list; // 将列表写成类的实例变量,以扩大它的可访问范围
     3     //注意这个List并不是java.util包下的.而是org.eclipse.swt.widgets.List;包下的.
     4     public void createPartControl(Composite parent) {
     5         IWorkbenchHelpSystem help = PlatformUI.getWorkbench().getHelpSystem();
     6         help.setHelp(parent, "cn.com.kxh.myplugin.buttonHelpId");
     7         Composite topComp = new Composite(parent, SWT.NONE);
     8         topComp.setLayout(new FillLayout());
     9         list = new List(topComp, SWT.BORDER);
    10         list.add("中国");
    11         list.add("美国");
    12         list.add("法国");
    13         // 列表选择事件监听
    14         list.addSelectionListener(new SelectionAdapter() {
    15             public void widgetSelected(SelectionEvent e) {
    16                 // 由IWorkbenchPage获得view2对象
    17                 IWorkbenchPage wbp = getViewSite().getPage();
    18                 //在插件中IWorkbenchPage对象比较重要,这里再给出一种获得此对象的通用的方法.
    19                 // Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
    20                 IViewPart view2 = wbp.findView("cn.com.kxh.myplugin.View2");
    21                 //这个地方的参数是"视图2"在plugin.xml中的id标识.由此可见plugin.xml文件在插件中的地位是极其重要的.
    22                 // 将当前选择的列表项显示在文本框中
    23                 Text text = ((View2) view2).getText();
    24                 text.setText(list.getSelection()[0]);
    25             }
    26         });
    27     }
    28     @Override
    29     public void setFocus() {}
    30 }

    View2.java (将View2.java的文本框对象改成类的实例变量,并编写相应的Setter和Getter方法)

     1 public class View2 extends ViewPart {
     2     private Text text;
     3     public void createPartControl(Composite parent) {
     4         Composite topComp = new Composite(parent,SWT.NONE);
     5         topComp.setLayout(new FillLayout());
     6         text = new Text(topComp,SWT.BORDER);
     7         text.setText("我是Text框");
     8     }
     9     public void setFocus() {}
    10     
    11     public Text getText() {
    12         return text;
    13     }
    14     public void setText(Text text) {
    15         this.text = text;
    16     }
    17 }

    SamplePerspective.java(和我的上一篇博客上没有做任何修改)

     1 public class SamplePerspective implements IPerspectiveFactory {
     2     // 参数IPageLayout是用于透视图的布局管理器
     3     public void createInitialLayout(IPageLayout layout) {
     4         // 得到本透视图的编辑空间标识
     5         String editorArea = layout.getEditorArea();
     6         // 在透视图左部创建一个空间,并将“视图1”放入其中。
     7         // "left"是此空间的标识;IPageLayout.LEFT指出此空间在透视图布局中的位置靠左;
     8         // 0.2f 指此空间占用透视图20%的宽度;editorArea 指使用透视图的编辑空间
     9         IFolderLayout left = layout.createFolder("left", IPageLayout.LEFT, 0.2f, editorArea);
    10         left.addView("cn.com.kxh.myplugin.View1"); // 参数为plugin.xml中“视图1”的id标识
    11         // 将“视图2”加入到透视图的底部
    12         IFolderLayout bottom = layout.createFolder("bottom", IPageLayout.BOTTOM, 0.8f, editorArea);
    13         bottom.addView(View2.class.getName());// 由于我们把视图的id取成和类全名一样,所以也可以用这种写法
    14         // 将以前定义的actionset(主菜单、工具栏按钮)加入到本透视图。这要在plugin.xml文
    15         // 件的action设置中将visible="false"才看得出效果,这时打开其他透视图,action设置的
    16         // 主菜单、工具栏按钮将不会出现在界面上,只有打开本透视图才会出现。
    17         layout.addActionSet("myplugin.actionSet");// 参数为actionSet在plugin.xml中的id标识
    18     }
    19 }

    总结:

    (1)在插件中IWorkbenchPage对象比较重要,这里再给出一种获得此对象的通用方法,不过他是获得当前活动的IWorkbenchPage对象.

    Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivepage();

    (2)IWorkbenchPage.findView("cn.com.kxh.myplugin.View2")中的参数为"视图2"在plugin.xml中设置的id标识.

    由此可见.plugin.xml文件在插件中的地位是及其重要的.IWorkbenchPage处理findView方法之外.还用findEditor方法来得到编辑器对象.像"cn.com.kxh.myplugin.View2"这种标识符在系统开发中会经常用到,最好建立一个类来集中放置这些字符串常量.然后系统中用的时候只用其常量名即可,否则把标识符的字串分散在代码中,以后改起来会非常麻烦.常量类的示例代码如下:

    public final class StringConstants{
        public final static String VIEW1="cn.com.kxh.myplugin.View1";
        public final static String VIEW2=View2.class.getName();
    }

    要用的时候时候直接类名点调用就可以了.

    附上上面代码的运行结果.

    第二种监听式:

    Eclipse环境的3个视图:"包资源管理器,大纲,属性"当双击包资源管理器中的结点时,大纲和属性视图也跟着改变.当然用前面讲的主动式来实现这个效果,不超过一个视图,用主动式就比较麻烦了,可以随着包资源管理器结点而需要改变的可能不止是大纲,属性视图,这时主动式就力所不及了.对于这种情况,则可以使用监听式.

      1.基本实例

      例如:View1,View2和View3视图,其中View2,View3需要监听View1中表格的选择事件.可以这样实现.

      (1)在View1类的createPartControl方法中加上如下一句:

      getSite().setSelectionProvider(tableViewer);//假设视图中有一个表格对象tableViewer

      setSelectionProvider方法的参数类型是ISelectionProvider(provider翻译为提供者),

      而TableViewer类正好实现了这一个接口(TreeViewer也一样).加此一句之后,如果再选择表格行时,

      底层事件机制将会通知所有监听者.

      (2)接着需要在View2,View3中各添加一个监听器到底层,一般也是写在createPartControl方法中.代码如下所示:

    1 getSite().getPage().addSelectionListener(new ISelectionListener(){
    2     public void selectionChanged(IWorkbenchPart part,ISelection selection){
    3         String partId = part.getSite().getId();
    4         if(partId.equals("cn.com.kxh.myplugin.View1")){
    5             System.out.println(part.getTitle());//part就是View1对象
    6             System.out.println(selection);//selection就是被选择的表格行所代表的记录对象
    7         }
    8     }
    9 });

    这样,就在View2,View3中截获了View1的选择事件.由于底层的选择提供者可能不仅仅是View1,所以才需要再View2,View3的监听代码中根据View1对plugin.xml中的id标识做一下判断.当然,也可以将这个判断交由底层来负责.如下所示:

    1 getSite().getPage().addSelectionListener("cn.com.kxh.myplugin.View1",new ISelectionListener(){
    2     public void selectionChanged(IWorkbenchPart part,ISelection selection){
    3             System.out.println(part.getTitle());//part就是View1对象
    4             System.out.println(selection);//selection就是被选择的表格行所代表的记录对象
    5     }
    6 });

    如果View1中有两个表格怎么办?像下面的这样是行不通的.

    getSite().setSelectionProvider(tableViewer1);

    getSite().setSelectionProvider(tableViewer2);

    既然是一个视图中只能设置一个选择提供者,那么可以换一种思路:创建一个自定义的选择提供者,然后由这个选择提供者收集tableViewer1,tableViewer2的选择事件集中传到底层.

    自定义选择提供者就需要实现ISelectionProvider接口,查了一下该接口的层次结构发现有一个SelectionProviderAdapter适配器类,可惜它不是public类,无法继承它.那么久将SelectionProviderAdapter的代码复制到如下的MySelectionProvider类中.并略做修改.

     1 class MySelectionProvider implements ISelectionProvider {
     2     List listeners = new ArrayList();
     3     ISelection theSelection = StructuredSelection.EMPTY;
     4 
     5     public void addSelectionChangedListener(ISelectionChangedListener listener) {
     6         listeners.add(listener);
     7     }
     8 
     9     public ISelection getSelection() {
    10         return theSelection;
    11     }
    12 
    13     public void removeSelectionChangedListener(
    14             ISelectionChangedListener listener) {
    15         listeners.remove(listener);
    16     }
    17 
    18     public void setSelection(ISelection selection) {
    19         theSelection = selection;
    20         final SelectionChangedEvent e = new SelectionChangedEvent(this, selection);
    21         Object[] listenersArray = listeners.toArray();
    22         
    23         for (int i = 0; i < listenersArray.length; i++) {
    24             final ISelectionChangedListener l = (ISelectionChangedListener) listenersArray[i];
    25             Platform.run(new SafeRunnable() {
    26                 public void run() {
    27                     l.selectionChanged(e);
    28                 }
    29             });
    30         }
    31     }
    32 }

    现在有了选择提供器,但是View1中两个表格选择事件的功能还没有实现,可以发现TableViewer有一个addSelectionChangedListener方法.它能够监听表格的选择事件,但它接受的参数类型是ISelectionChangedListener.可以再单独创建一个ISelectionChangedListener接口的实现类,也可以让MySelectionProvider实现此接口.从而让MySelectionProvider即是底层的选择提供者,又是表格的选择事件的监听者.这里采用后一方案,让MySelectionProvider再实现ISelectionChangedListener接口.如下所示:

    class MySelectionProvider implements ISelectionProvider,ISelectionChangedListener{

      ...原代码不改变.省略

      public void selectionChanged(SelectionChangedEvent event){

        setSelection(event.getSelection());

      }

    }

     View2,View3中的代码不必修改,只需要把View1类中的相应代码修改如下:

    MyselectionProvider selectionProvider = new MySelectionProvider();

    tableViewer1.addSelectionChangedListener(selectionProvider);

    tableViewer2.addSelectionChangedListener(selectionProvider);

    getSite().setSelectioinProvider(selectionProvider);

    这里只提到了视图,实际上任何WorkbenchPart的子类都可以使用这种机制,包括编辑器,另外,由于可以创建自定义选择提供者,所以可以不仅局限于监听TreeViewer或者TableViewer,也可以监听Combo,Text等组件的非选择事件,只需要将要传送的信息包装成一个ISelection对象传给MySelectionProvider.setSelection方法既可.下面的代码就可以使得View1中的文本框组件的每次击键字符传播给各个视图的监听器.

    final MySelectionProvider selectionProvider = new MySelectionProvider();

    text.addKeyListener(new KeyListener(){

      public void keyPressed(KeyEvent e){

        String s = String.valueOf(e.character);

        ISelection selection = new StructuredSelection(s);

        selectionProvider.setSelection(selection);

      }

      public void keyReleased(KeyEvent e){}

    });

    注意:滥用底层事件广播机制可能会对性能有影响,但这需要用户在实际开发中做出测试和评估,以确定方法是否真的对性能造成了影响,而不是想当然.

  • 相关阅读:
    js窗口拖动 模版
    js中准确判断数据类型的方法
    ArcGis Python脚本——批量对影像、要素类定义投影
    ArcGis 属性表.dbf文件使用Excel打开中文乱码的解决方法
    解析ArcGis拓扑——根据拓扑错误记录提取shp文件、导出Excel表格
    解析ArcGis拓扑——检查的流程,以面重叠检查为例
    ArcGis Classic COM Add-Ins插件开发的一般流程 C#
    解析ArcGis的标注(三)——标注的放置 与 转注记修改
    解析ArcGis的标注(二)——认识ArcGis标注标签
    解析ArcGis的标注(一)——先看看分数式、假分数式标注是怎样实现的
  • 原文地址:https://www.cnblogs.com/DreamDrive/p/4173614.html
Copyright © 2011-2022 走看看