从组合框控件看SWT与JFace的区别
发布者:
Wenzhe
Combo是SWT的组合框,ComboViewer是JFace的组合框,都是组合框,ComboViewer其实就 是在Combo上面加上MVC的封装。记住下面的公式:
JFace = SWT + MVC
比如说要实现如下图的任务,选中一本书,显示它的价格。
首先定义领域类(Domain Class),如下所示:
/** * @author liuwenzhe2008@qq.com */ public class Book { private String name = ""; private int price = 0; public Book(String name, int price) { this.name = name; this.price = price; } public String getName() { return name; } public int getPrice() { return price; } }
现在有个书架,摆了好几本书:
Book[] books = new Book[] { new Book("Java", 20), new Book("SWT", 30), new Book("JFace", 40), new Book("Eclipse RCP", 50) };
下面第一种方案采用SWT的Combo:
final Combo combo = new Combo(shell, SWT.READ_ONLY); combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
把书架的书放在combo里面:
for (Book book : books) {
combo.add(book.getName());
}
考虑到每一本书有不同的价格,换另一本书时就需要在更新价格控件,这样需要为Combo增加事件响应:
combo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
int index = combo.getSelectionIndex();
Book book = books[index];
text.setText(Integer.toString(book.getPrice()));
}
});
可以看到,SWT的Combo主要是通过索引(index)来访问item的,这样不够直接,也不够方便。 下面看看JFace的ComboViewer是怎么实现以上功能的。
首先定义一个ComboViewer控件:
ComboViewer comboViewer = new ComboViewer(shell, SWT.NONE);
需要的话,你也可以从ComboViewer中拿到SWT的Combo控件:
Combo combo = comboViewer.getCombo();
combo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
由于JFace采用MVC模式,需要我们先回答3个问题:
- 1、你要往控件输入(Input)什么东西?这相当于MVC模式中的模型(Model), 可以是任意引用类型(即Object及其子类,只要不是int这些基本类型就行)。
这里我们需要往comboViewer输入书架上的书本,即:
comboViewer.setInput(books);
- 2、控件如何组织它的内容?也就是需要找一个内容提供者(ContentProvider), 这相当于MVC模式中的控制器(Controller),必须实现IContentProvider接口。
作为输入的书本已经是数组了,因此我们可以考虑使用JFace专门为数组(array,List,Vector) 提供的实现类ArrayContentProvider,即:
comboViewer.setContentProvider(new ArrayContentProvider());
- 3、控件如何显示?也就需要找一个标签提供者(LabelProvider),这相当于MVC模式中的视图(Viewer), 必须实现ILabelProvider接口。
这里我们只需要显示书名就可以了,即:
comboViewer.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
assert element instanceof Book;
Book book = (Book)element;
return book.getName();
}
});
好啦,通过回答以上3个问题,总算把书架上的书放到ComboViewer上了。累吧?你是不是觉得还 不如SWT的Combo方便,一个for循环就搞定了,MVC搞得这么麻烦,是吧?有得必有失,有失必有得, MVC给我们带来更多的灵活性和可扩展性。先喝杯咖啡吧,听我慢慢道来,待会你会永远抛弃Combo, 而衷心地爱上ComboViewer的。废话少说,我们先继续吧。
同样地,考虑到每一本书有不同的价格,换另一本书时就需要在更新价格控件,这样需要为ComboViewer 增加事件响应:
comboViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
assert selection instanceof StructuredSelection;
StructuredSelection ss = (StructuredSelection)selection;
Object obj = ss.getFirstElement();
if (obj instanceof Book) {
Book book = (Book)obj;
text.setText(Integer.toString(book.getPrice()));
}
}
});
看起来比SWT Combo的事件响应要复杂点,但你发现没有,这里不再通过索引(index)来访问元素(item) ,而是直接访问。你可以会想,这又有什么所谓呢?
这么简单的需求,现在当然用哪种方法都无所谓。但客户总是得寸进尺的,软件总是善变的,好的软件设计一定要拥抱变化。 好啦,客户A提出第一个改进的需求:他看书喜欢带书名号,如“《SWT》”。 采用SWT方案的工程师说简单,只要在把书架的书放进Combo时加上书名号就OK了,即:
combo.add(“«” + book.getName() + “»”);
采用JFace方案的工程师也说简单,这个只是显示的问题,就交给视图(Viewer)吧,只要在LabelProvider函数输出加书名 号就OK,即:
comboViewer.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
assert element instanceof Book;
Book book = (Book)element;
return "<<" + book.getName() + ">>";
}
每个人的兴趣爱好都是不同的,那问题来了,客户B认为简单才是最美,就是不喜欢显示书名号,但考虑到客户A的感受, 希望我们加一个复选框(CheckBox),勾上显示书名号,不勾就不显示书名号。
这时候SWT方案就头痛了,那把书架的书放进Combo是究竟要不要加书名号,两个客户都不能得罪啊。不要怪客户的需求太BT, 这就是SWT方案没有视图的后果。
JFace方案笑了,可以很轻松的解决:
comboViewer.setLabelProvider(new LabelProvider() {
@Override
public String getText(Object element) {
assert element instanceof Book;
Book book = (Book)element;
if (btnShowBookMark.getSelection()) {
return "<<" + book.getName() + ">>";
} else {
return book.getName();
}
}
客户C来了,他希望书名可以排序,比较书”Eclipse”总是排在”SWT”前面。但为了兼顾其他客户, 我们需要再加一个复选框(CheckBox),勾上为排序,不勾不排序。
这个需求对于SWT方案又是重拳一击,他快晕倒了,这就是依赖于索引(index)的结果。
JFace方案又笑了,简单啊,谁叫JFace控件天生就有比较器(Comparator)呢?看看下面的吧, 该羡慕嫉妒恨了吧。
comboViewer.setComparator(new ViewerComparator() {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
return 0;
if (!btnSort.getSelection()) {
}
return super.compare(viewer, e1, e2);
}
});
客户D来了,她是个富婆,看不起穷人,只卖贵的,不买对的,她不希望看到35块钱以下的书 (包括35块也不行),把这些书通通过滤调。但为了兼顾一下像我们这样的苦孩子, 我们需要再加一个复选框(CheckBox),勾上为过滤,不勾不过滤。
这个需求对于SWT方案更加的BT,SWT方案这回彻底疯掉了,为什么有这么多刁钻的客户呀? JFace方案还是笑了,这样的客户多多益善啊,谁叫JFace控件天生就有过滤器(Filter)呢?
comboViewer.addFilter(new ViewerFilter() {
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (!btnFilter.getSelection()) {
return true;
}
assert element instanceof Book;
Book book = (Book)element;
return book.getPrice() > 35;
}
});
看看上面的实现吧,SWT方案们,JFace的大门永远为你们打开的,过来学学JFace吧!
睿初科技软件开发技术博客,转载请注明出处
blog comments powered by Disqus
发布日期
标签
最近发表
- volatile与多线程
- TDD practice in UI: Develop and test GUI independently by mockito
- jemalloc源码解析-核心架构
- jemalloc源码解析-内存管理
- boost::bind源码分析
- 小试QtTest
- 一个gtk下的目录权限问题
- Django学习 - Model
- Code snippets from C & C++ Code Capsule
- Using Eclipse Spy in GUI products based on RCP
文章分类
- cpp 3
- wxwidgets 4
- swt/jface 1
- chrome 3
- memory_management 5
- eclipse 1
- 工具 4
- 项目管理 1
- cpplint 1
- 算法 1
- 编程语言 1
- python 5
- compile 1
- c++ 7
- 工具 c++ 1
- 源码分析 c++ 3
- c++ boost 2
- data structure 1
- wxwidgets c++ 1
- template 1
- boost 1
- wxsocket 1
- wxwidget 2
- java 2
- 源码分析 1
- 网路工具 1
- eclipse插件 1
- django 1
- gtk 1
- 测试 1
- 测试 tdd 1
- multithreading 1