什么是MVC?
MVC体系结构(或设计模式)是一种图形用户界面(GUI)设计样式,由三部分组成:模型,视图和控制器。 MVC将表示与数据分离,并将表示与对数据的操作分离。
实施MVC体系结构与其他类型的应用程序不同。 主要区别在于您如何放置和实现业务逻辑或查看呈现逻辑。 与典型的Web应用程序不同,在常规Web应用程序中,程序员必须设计和实现所有MVC部分,Eclipse提供了一个API,该API可以为您完成大部分控制或渲染。 因此,不能严格将Eclipse的MVC实现与Web或任何其他应用程序类型的MVC实现进行比较。
Eclipse JFace
Eclipse JFace使用内容提供者和标签提供者来实现MVC架构。 JFace API包装标准(非平凡)的小部件,例如表和树,并实现结构化的内容提供程序和标签提供程序。 您可以根据窗口小部件类型实现不同的内容提供程序。 面向列表的查看器将实现结构化的查看器,其中内容以结构化(列出)的方式映射到小部件项目。
基类称为Viewer
,它是结构化查看器的扩展。 查看者充当小部件容器。 内容提供者以结构化的方式获取数据; 类似地,标签提供者获得相应的标签。 JFace查看器实现检索此数据,设置相应的关联,并使用数据集更新用户界面(UI)组件。 它还选择,过滤和排序。
如何实施JFace
Eclipse View
和Viewer
执行大多数JFace控制功能。 Viewer
或MVC的View部分,还充当小部件容器; 这是演示组件。
Eclipse View
实例化Viewer
,内容提供者和标签提供者,它们充当模型,保存值对象,并将它们在Viewer
为inputElement
。
要创建View
,请使用createPartControl()
方法实例化Viewer
。 清单1实例化了默认的树查看器; 您还可以通过使用带有树对象作为参数的构造函数来自定义树并实例化树查看器。
清单1. ExampleView的CreatePartControl方法
public class ExampleView extends ViewPart
{ ... public void createPartControl(Composite parent)
{ // define a grid layout
GridLayout layout = new GridLayout();
layout.numColumns = 1;
layout.marginHeight = 0;
layout.marginWidth = 0; l
ayout.horizontalSpacing = 0;
layout.verticalSpacing = 1;
parent.setLayout(layout);
// create widgets createActionBar(parent);
createTree(parent);
// add context menu and listeners
viewer.addDoubleClickListener(this); viewer.addSelectionChangedListener(openAction);
// register viewer so actions respond to selection getSite().setSelectionProvider(viewer);
hookContextMenu();
}
private void createTree(Composite parent)
{
viewer = new TreeViewer(parent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
viewer.setContentProvider(new ExampleViewContentProvider()); viewer.setLabelProvider
(new ExampleViewLabelProvider());
viewer.setSorter(new ViewerSorter());
viewer.setInput(ModelManager.getExampleModel());
viewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
} ... }
在一个单独的类中,实现ContentProvider
,这是一个对象,该对象使用与您的查看器类型相对应的接口向视图提供数据。 例如,您可以实现IStructuredContentProvider
或ITreeContentProvider
查看器。
通过在ContentProvider
代码中实现以下方法之一,将ContentProvider
与Viewer
:
- getElements(父对象)
- getChildren(Object元素)
注意:JFace框架将调用这些方法。
清单2.创建一个自定义ContentProvider
public class ExampleViewContentprovide implements ITreeContentProvide {
MVC体系结构通常涉及多个视图和单个数据源。 当前,在Eclipse平台中,您只能将一个视图与单个模型关联。 但是,您也可以创建多个视图,这些视图可以使用适配器视图来访问相同的数据。 只需在ContentProvider
类中包含inputChanged()
方法。 每当Viewer
有一个新的输入集时,它就会使用inputChanged()
方法通知ContentProvider
。 inputChanged()
方法接受Viewer
作为输入参数,因此多个视图可以使用单个ContentProvider
。
清单3.对不同的查看器使用inputChanged方法
/** * Register content provider with model. */
public void inputChanged(Viewer viewer, Object oldInput, Object newInput)
{
if (newInput != null)
{
this.viewer = viewer;
this.model = (ExampleDelegate)newInput; this.model.addModelListener(this);
}
}
将MVC与Eclipse SWT结合使用
在大多数常见的GUI应用程序中,您创建一个布局以显示所请求的数据或完成一个表单(如UI)以添加或修改数据。 图1中的示例应用程序显示了如何以定制形式从XML存储中以可读和可编辑模式显示数据。 它还说明了每个组件相对于MVC架构的作用。
图1.示例应用程序
图2显示了应用程序的类图,以帮助您更好地了解整体架构。
图2.示例应用程序的类图
创建一个控件
ExampleView
充当整个应用程序的容器。 它将使用createPartControl
方法初始化应用程序。
清单4. CreatePartControl方法初始化布局
public void createPartControl(Composite parent) {
ExampleEditLayout _layout = new
ExampleEditLayout(parent,SWT.NONE,FieldMode.Read,new ExampleViewContentProvider());
}
创建表单和布局
基本布局类定义了全局方法和不同表单应用程序使用的声明。 在此注册了一些充当回调机制的容器事件。
清单5.布局的CreateControl方法
public void createControls(int style) {
GridData gridData;
Text textFld, subjectFld;
Control toLabel, ccLabel, bccLabel;
Control fromDateTime;
Control control;
Button durationText;
Button submit;
GridLayout layout = new GridLayout(2, false);
layout.marginWidth = 0;
layout.marginHeight = 4;
setLayout(layout);
//Label
gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_CENTER);
gridData.horizontalIndent = 10;
LabelFactory.create(this,
Messages.getString("ExampleEditLayout.Title"), gridData); //$NON-NLS-1$
gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_CENTER);
gridData.horizontalIndent = 40;
LabelFactory.create(this, "", gridData);
//Text
gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_CENTER);
gridData.horizontalIndent = 10;
control = LabelFactory.create(this,
Messages.getString("ExampleEditLayout.Email"), gridData); //$NON-NLS-1$
gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING
| GridData.VERTICAL_ALIGN_CENTER);
gridData.horizontalIndent = 10;
control = TextFactory.create(this,
SWT.BORDER | SWT.V_SCROLL | SWT.WRAP, gridData, FieldMode.Edit); //$NON-NLS-1$
addField(new TextField(control, ExampleViewContentProvider.FIRST_INDEX));
//Combo
gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_CENTER);
gridData.horizontalIndent = 10;
LabelFactory.create(this,
Messages.getString("ExampleEditLayout.Group"), gridData); //$NON-NLS-1$
gridData = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING
| GridData.VERTICAL_ALIGN_CENTER);
gridData.horizontalIndent = 40;
control = ComboFactory.create(this,
FieldMode.Edit, false, gridData); //$NON-NLS-1$
addField(new ComboField(control,
ExampleViewContentProvider.SECOND_INDEX));
...}
创建一个字段(视图)
Field
是一个抽象类,用于定义包含各种UI控件的方法以及用于全局标识这些控件的关联ID。 每个UI控件都将子类化为Field
并赋予内容提供者读写能力。 清单6使用Layout
类中的Factory模式创建一个Field
。
清单6.使用Field类创建文本对象
public class TextField extends Field {
/**
* @param control
* @param id
*/
public TextField(Control control, int id) {
super(control, id);
}
/* Based on the ID of the widget, values retrieved from
* the content provider are set.
*/
public void readFromContent(IExampleContentProvider content) {
String newText = (String )content.getElement(getId());
if (newText != null)
((Text )_control).setText(newText);
}
/* Based on the ID of the widget, values retrieved from widget are
* sent back to the content provider.
*/
public void writeToContent(IExampleContentProvider content) {
String newText = ((Text )_control).getText();
content.setElement(getId(), newText);
}
}
简化内容提供者(模型)
ExampleViewContentProvider
充当扩展IStructuredContentProvider
的模型侦听器。 它是Eclipse API的简单实现,提供了回调以检索数据。 每个请求数据的项目都基于视图创建期间在布局中定义的项目唯一ID。
方法调用将返回与定义的每个全局ID相关联的数据。 在清单7所示的内容提供程序中,您可以使用适配器从XML文件或数据库中检索数据。
清单7.在自定义ContentProvider中实现方法
public Object getElement(int iIndex) {
switch (iIndex) {
case FIRST_INDEX: return "developer@ibm.com";
case SECOND_INDEX : return new Integer(1);
case FOURTH_INDEX : return new Boolean(true);
case THIRD_INDEX: return new Boolean(false);
case FIFTH_INDEX: return new Boolean(false);
}
return null;
}
创建控件并初始化布局后,表单将要求内容提供者使用控件ID的数据填充表单控件。
清单8.初始化Layout并填充控件的表单
public Form (Composite parent, int style, FieldMode mode, ExampleViewContentProvider content) {
super(parent, style);
_content = content;
_style = style;
setMode(mode);
init(style);
}
private void init(int style) {
createControls(style);
controlsCreated();
}
protected void controlsCreated() {
readFromContent();
}
结论
Web应用程序是MVC架构样式的早期实现者。 但是,随着像Eclipse这样的简单而强大的应用程序开发平台的到来,程序员可以在更短的时间内以最小的复杂度轻松开发更丰富的UI。
翻译自: https://www.ibm.com/developerworks/java/library/wa-eclipsemvc/index.html