首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

20.3  在视图之间实现事件监听

两个视图中的组件之间的互动,在开发插件时是经常碰到的问题。例如,在图20.3所示界面中,单击视图1列表的某项时,视图2的文本框显示相应字符。本节将实现此功能。

20.3.1  主动式

主动式就是在视图1的代码中获取对视图2的对象引用,然后将视图1中的对象主动地传给视图2。具体实现如下所示:

1.修改View1.java、View2.java

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

IWorkbenchPage wbp = getViewSite().getPage();

IViewPart view2 = wbp.findView("cn.com.chengang.myplugin.View2");

得到了视图2的对象后,其他一切就容易了,先给出修改后View1.java如下:

public class View1 extends ViewPart {

    public void createPartControl(Composite parent) {

        Composite topComp = new Composite(parent, SWT.NONE);

        topComp.setLayout(new FillLayout());

        final List list = new List(topComp, SWT.BORDER);

        list.add("中国");

        list.add("美国");

        list.add("法国");

        //列表选择事件监听

        list.addSelectionListener(new SelectionAdapter() {

            public void widgetSelected(SelectionEvent e) {

                //由IWorkbenchPage获得view2对象

                IWorkbenchPage wbp = getViewSite().getPage();

                IViewPart view2 = wbp.findView("cn.com.chengang.myplugin.View2");

                if (view2==null)  return; //避开空值

                //将当前选择的列表项显示在文本框中

                Text text = ((View2) view2).getText();

                text.setText(list.getSelection()[0]);

            }

        });

    }

    public void setFocus() {}

}

然后将View2.java的文本框对象改成类的实例变量,并编写它相应的Setter/Getter方法:

public class View2 extends ViewPart {

    private Text text;

    public void createPartControl(Composite parent) {

        Composite topComp = new Composite(parent, SWT.NONE);

        topComp.setLayout(new FillLayout());

        text = new Text(topComp, SWT.BORDER); //注意:text前的类型定义已去除

        text.setText("我是text框");

    }

    public void setFocus() {}

    //文本框text相应的Setter/Getter方法

    public Text getText() {return text;}

    public void setText(Text text) {this.text = text;}

}

2.总结

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

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

(2)IWorkbenchPage.findView("cn.com.chengang.myplugin.View2")中的参数为“视图2”在plugin.xml中设置的id标识。由此可见,plugin.xml文件在插件中的地位是极其重要的。IWorkbenchPage除了findView方法之外,还用findEditor方法来得到编辑器对象。

像“cn.com.chengang.myplugin.View2”这种标识符在系统开发中会经常用到,最好建一个类来集中放置这些字符串常量,然后系统中用的时候只用其常量名即可,否则把标识符的字串分散在代码中,以后改起来会非常麻烦。常量类的示意代码如下:

public final class StringConstants {

    public final static String VIEW1 = "cn.com.chengang.myplugin.View1";

    public final static String VIEW2 = View2.class.getName();

}

要用的时候则这样写:

IViewPart view2 = wbp.findView(StringConstants.VIEW2);

20.3.2  监听式

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方法中,代码如下所示:

getSite().getPage().addSelectionListener(new ISelectionListener() {

         public void selectionChanged(IWorkbenchPart part, ISelection selection) {

                   String partId=part.getSite().getId();

                   if (partId.equals("cn.com.chengang.myplugin.View1")){

                            System.out.println(part.getTitle()); //part就是View1对象

                            System.out.println(selection); //selection就是被选择的表格行所代表的记录对象

                   }

         }

});

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

getSite().getPage().addSelectionListener("cn.com.chengang.myplugin.View1",new ISelectionListener() {

         public void selectionChanged(IWorkbenchPart part, ISelection selection) {

                   System.out.println(part.getTitle()); //part就是View1对象

                   System.out.println(selection); //selection里包含了被选择的表格行记录对象

         }

});

2.进阶实例

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

getSite().setSelectionProvider(tableViewer1);

getSite().setSelectionProvider(tableViewer2);

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

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

class MySelectionProvider implements ISelectionProvider{

    List listeners = new ArrayList();

    ISelection theSelection = StructuredSelection.EMPTY;

    public void addSelectionChangedListener(ISelectionChangedListener listener) {

        listeners.add(listener);

    }

    public ISelection getSelection() {

        return theSelection;

    }

    public void removeSelectionChangedListener(ISelectionChangedListener listener) {

        listeners.remove(listener);

    }

    public void setSelection(ISelection selection) {

        theSelection = selection;

        final SelectionChangedEvent e = new SelectionChangedEvent(this, selection);

        Object[] listenersArray = listeners.toArray();

        for (int i = 0; i < listenersArray.length; i++) {

            final ISelectionChangedListener l = (ISelectionChangedListener) listenersArray[i];

            SafeRunner.run(new SafeRunnable() {

                public void run() {

                    l.selectionChanged(e);

                }

            });

                   }

    }

}

现在有了选择提供器,但是收集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().setSelectionProvider(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) {}

});

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

查看所有评论(0)条】

最近评论



正在载入评论列表...
热点评论