首先介绍一下我们要达到的效果,如下图所示:
可以看到,用户点击左边视图上的人员列表,该人员的详细信息会显示在右侧的view视图中,这一步骤看起来简单,但是要做的工作却不少,下面我们就着手把前期获得的RCP程序做成这个样子,让View之间传递信息或者更复杂一些的对象。
从Eclipse目前提供的手段看来,我们可以使用下列方法实现视图的交互:
(1)选择提供器 - 选择监听器(selection provider-selection listener)模式,从而让视图对其他视图中的选择做出反应
(2)使用属性改变监听模式,即Property Changed Listener模式,用于视图中没有可供点击的UI模块的情况下。这类监听模式允许视图将属性改变事件
以下将详细介绍这两种模式的概念、适用场景,并结合我们的Hello RCP分别实例说明这两种视图交互模式的实现。
(一)选择提供器-选择监听器(selection provider-selection listener)模式:
这是一种传统的事件传递模式,一般来说,只要视图中的UI控件实现了ISelectionProvider接口,即具备提供选择事件的能力,就可以使用这个模式将自身发生的选择事件提供给其他实现了ISelectionListener的UI控件。例如我们在Hello RCP中实现的Navigation视图,里面采用了ListViewer这一控件,而Jface中所有的Viewer对象都实现了ISelectionProvider接口,那么当我们点击navigation视图list列表中的人员名单时,ListViewer列表就可以向其他能够监听该选择事件的对象提供该选择事件,如果我们在事件中包含一些字符串信息,那么其他对象得到这个信息之后,就可以进行相应显示了。
“Eclipse提供了所谓的Site,以及ISelectionService机制,来处理试图之间的简单的交互。简单的说,ViewSite提供了一个交互的中心点,其它View向ViewSite提供选择事件,或者向其注册监听器,而事件的触发与转发则由ViewSite()来完成。”
以上只是一些概念介绍,对于我们来说,只需按照下列步骤进行,就可以将一个视图变成一个提供Selection 事件的Selection Provider:
(1)首先将视图注册成为Selection Provider,即实现ISelectionProvider接口
1
(2)有了以上步骤还不够,还需要将视图中具体的Viewer上想要发生的事件,注册到这个Provider上。(3)一个Selection Provider想要其他部件监听的话,还要向Site中控台进行注册,要不然就相当于开会时找不到话筒讲话,大家听不见
1
this.getSite().setSelectionProvider(this);
注意this对象指的是Viwe视图,它具有指向Site的引用,通过getSite()方法获得引用(4)最后,还要把讲给听众听,没有听众也是白讲,这里是在setSelection()方法里迭代每一个注册了ISelectionListener的控件,找到它们,把事件传递给这些听众即可:
至此,我们已经实现了一个Selection Provider了,对于事件监听的另一端,即Selection Listener,则更为简单一些。只需要实现ISelectionListener接口,并注册在Site中:
然后实现public void selectionChanged(IWorkbenchPart part, ISelection selection) {}方法即可。这样,当SelectionProvider中的选择发生改变时,这个视图中的selectionChanged()方法就会被调用。
1
}
根据以上介绍的Selection Provider-Selection Listener模式,我们重新改造了一下navigation view视图和detail view视图:
1
package hellorcp;
2
3
import java.util.ArrayList;
4
import java.util.Iterator;
5
6
import org.eclipse.jface.action.IToolBarManager;
7
import org.eclipse.jface.viewers.ISelection;
8
import org.eclipse.jface.viewers.ISelectionChangedListener;
9
import org.eclipse.jface.viewers.ISelectionProvider;
10
import org.eclipse.jface.viewers.IStructuredContentProvider;
11
import org.eclipse.jface.viewers.ListViewer;
12
import org.eclipse.jface.viewers.SelectionChangedEvent;
13
import org.eclipse.swt.SWT;
14
import org.eclipse.swt.widgets.Composite;
15
import org.eclipse.ui.part.ViewPart;
16
import hellorcp.NavigationViewLabelProvider;
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
package hellorcp;
2
3
import java.util.ArrayList;
4
5
import org.eclipse.jface.viewers.ISelection;
6
import org.eclipse.jface.viewers.IStructuredSelection;
7
import org.eclipse.jface.viewers.TableViewer;
8
import org.eclipse.swt.SWT;
9
import org.eclipse.swt.widgets.Composite;
10
import org.eclipse.swt.widgets.Group;
11
import org.eclipse.swt.widgets.Label;
12
import org.eclipse.swt.widgets.Table;
13
import org.eclipse.swt.widgets.Text;
14
import org.eclipse.ui.ISelectionListener;
15
import org.eclipse.ui.IWorkbenchPart;
16
import org.eclipse.ui.part.ViewPart;
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
将以上文件重新编译,再运行我们的Hello RCP,可以看到,点击Navigation Views时,已经可以将选择的人员信息传递给detal view了,我们的视图真正动了起来:
其实对于本例来说,由于JFace Viewer已经实现了ISelectionProvider 接口,因此还有一种更简便的方法实现上述效果,就是将navigation view中的list viewer直接注册为Selection Provider ,这样就可以省去实现ISelectionProvider接口的代码了:
以下是NavigationViewPart.java的另外一种实现方式:
1
package hellorcp;
2
3
import java.util.ArrayList;
4
import java.util.Iterator;
5
6
import org.eclipse.jface.action.IToolBarManager;
7
import org.eclipse.jface.viewers.ISelection;
8
import org.eclipse.jface.viewers.ISelectionChangedListener;
9
import org.eclipse.jface.viewers.ISelectionProvider;
10
import org.eclipse.jface.viewers.IStructuredContentProvider;
11
import org.eclipse.jface.viewers.ListViewer;
12
import org.eclipse.jface.viewers.SelectionChangedEvent;
13
import org.eclipse.swt.SWT;
14
import org.eclipse.swt.widgets.Composite;
15
import org.eclipse.ui.part.ViewPart;
16
import hellorcp.NavigationViewLabelProvider;
17
18
对于detail view ,如果将将消费者视图作为监听器注册到特定的视图部分,就不用循环所有的Listener来通知了,这样可以节约更多的系统资源了。2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
package hellorcp;
2
3
import java.util.ArrayList;
4
5
import org.eclipse.jface.viewers.ISelection;
6
import org.eclipse.jface.viewers.IStructuredSelection;
7
import org.eclipse.jface.viewers.TableViewer;
8
import org.eclipse.swt.SWT;
9
import org.eclipse.swt.widgets.Composite;
10
import org.eclipse.swt.widgets.Group;
11
import org.eclipse.swt.widgets.Label;
12
import org.eclipse.swt.widgets.Table;
13
import org.eclipse.swt.widgets.Text;
14
import org.eclipse.ui.ISelectionListener;
15
import org.eclipse.ui.IWorkbenchPart;
16
import org.eclipse.ui.part.ViewPart;
17
18
看起来后两种实现是不是比前面的要轻便很多呢?2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
但是对于我们来讲,视图间以Selection Provider 和Listener模式传递消息还存在很多局限:
1 视图可能希望公布其他信息,而不只是公布可视化选择信息。公布的信息可能是根据选择进行某些后期处理的结果。
2 视图可能希望使用来自另一个插件的信息,而这个插件可能根本没有提供视图(使用包含的 JFace 查看器)。在这种情况下,使用基于 UI 选择的链接是不可能的
对于以上问题,通过自动方式进行就很困难了,需要我们手工解决,而为视图注册属性监听器而实现观测其它视图的属性变化是个不错的替代模式。
(二)属性改变监听器模式:
属性改变监听器模式主要通过使用JFace中一个重要的接口org.eclipse.jface.util.IPropertyChangeListener来实现,通过注册该监听器,以及使用IPropertyChangeEvent,可以达到事件传递的目的。
与Selection provider-listener模式不同的是,属性改变监听器可以定义到插件上,由插件本身提供注册列表,如下所示:
1
ArrayList myListeners = new ArrayList();
2
// A public method that allows listener registration
3
}
2
3
当插件想要把产生的事件通知到各个监听器的时候,就对这个注册列表中每个Listener元素进行迭代,逐一通知,这样每个Property Change Event就传播到了各个Listener,由后者进行处理了,这个调用模式如下所示:
1
}
总而言之,要想实现这个模式,我们必须自己新定义一个注册并调用Property Change Event的类,我们把它叫做:PersonPlugin.java
那么接下来对于我们的navigation view中的list来说,由于没有采用provider模式,那么就必须自己定义它的SelectionChangeListener了,我们可以在这个ListViewer的添加该Listener中实现我们的目的:
1
package hellorcp;
2
3
import java.util.ArrayList;
4
import java.util.Iterator;
5
6
import org.eclipse.jface.action.IToolBarManager;
7
import org.eclipse.jface.util.IPropertyChangeListener;
8
import org.eclipse.jface.viewers.ISelection;
9
import org.eclipse.jface.viewers.ISelectionChangedListener;
10
import org.eclipse.jface.viewers.ISelectionProvider;
11
import org.eclipse.jface.viewers.IStructuredContentProvider;
12
import org.eclipse.jface.viewers.IStructuredSelection;
13
import org.eclipse.jface.viewers.ListViewer;
14
import org.eclipse.jface.viewers.SelectionChangedEvent;
15
import org.eclipse.swt.SWT;
16
import org.eclipse.swt.widgets.Composite;
17
import org.eclipse.ui.part.ViewPart;
18
19
import hellorcp.Person;
20
import hellorcp.PersonPlugin;
21
import hellorcp.NavigationViewLabelProvider;
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
注意我们为listviewer添加了Selection Change Listener 方法,并通知到了PersonPlugin。
接着,在detail view中,我们只用实现IPropertyChangeListener即可,以下是detail view的代码:
1
package hellorcp;
2
3
import java.util.ArrayList;
4
5
import org.eclipse.jface.util.IPropertyChangeListener;
6
import org.eclipse.jface.viewers.ISelection;
7
import org.eclipse.jface.viewers.IStructuredSelection;
8
import org.eclipse.jface.viewers.TableViewer;
9
import org.eclipse.swt.SWT;
10
import org.eclipse.swt.widgets.Composite;
11
import org.eclipse.swt.widgets.Group;
12
import org.eclipse.swt.widgets.Label;
13
import org.eclipse.swt.widgets.Table;
14
import org.eclipse.swt.widgets.Text;
15
import org.eclipse.ui.ISelectionListener;
16
import org.eclipse.ui.IWorkbenchPart;
17
import org.eclipse.ui.part.ViewPart;
18
19
import hellorcp.PersonPlugin;
20
21
import hellorcp.Person;
22
23
采用属性改变监听模式能够更加灵活地在插件之间、插件的各个view之间传递信息,突破了传递信息必须与UI相关的局限,而且还可以异步传递信息,这些信息可以是插件后台JOB定期运行获得的信息,以及定期从数据库中获得的信息等等。不难看到,属性改变监听器扩展了插件之间,视图之间,前台与后台之间的消息传递场景,是我们开发Eclipse RCP应用更好的选择。2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23