在自定义SWT组件中实现MVC

举报
Amrf 发表于 2020/10/29 14:43:36 2020/10/29
【摘要】 前面有篇博客说到一个基于swing的数据分析工具,通过进一步的分析我发现我的说法错了,那个工具的核心底座是swt而不是swing;下面这篇文章翻译自ibm社区,原文最后有相关演示的代码,06年的文章了...测试效果:演示代码缺少META-INF/MANIFEST.MF会导致缺少相关插件的依赖编译报错,添加如下:Manifest-Version: 1.0Bundle-ManifestVersi...

前面有篇博客说到一个基于swing的数据分析工具,通过进一步的分析我发现我的说法错了,那个工具的核心底座是swt而不是swing;

下面这篇文章翻译自ibm社区,原文最后有相关演示的代码,06年的文章了...

  • 测试效果:

image.png

  • 演示代码缺少META-INF/MANIFEST.MF会导致缺少相关插件的依赖编译报错,

添加如下:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: ExampleViewer
Bundle-SymbolicName: ExampleViewer;singleton:=true
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: ExampleViewer.ExampleViewerPlugin
Bundle-Vendor: PLUGIN
Require-Bundle: org.eclipse.ui,
  org.eclipse.core.runtime,
  org.eclipse.core.resources,
  org.eclipse.jface.text,
  org.eclipse.ui.editors,
  org.eclipse.ui.genericeditor,
  org.eclipse.core.filebuffers,
  org.eclipse.ui.navigator,
  org.eclipse.ui.navigator.resources,
  org.eclipse.ui.ide,
  org.eclipse.ui.intro,
  org.eclipse.ui.intro.universal,
  org.eclipse.ui.console,
  org.eclipse.jdt.ui,
  org.eclipse.swt,
  org.eclipse.jface,
  org.eclipse.ui.workbench
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy


下面是原文的翻译转载:

什么是MVC?

MVC体系结构(或设计模式)是一种图形用户界面(GUI)设计样式,由三部分组成:模型,视图和控制器。MVC将表示与数据分离,并将表示与对数据的操作分离。

实施MVC体系结构与其他类型的应用程序不同。主要区别在于您如何放置和实现业务逻辑或查看呈现逻辑。与典型的Web应用程序不同,在常规Web应用程序中,程序员必须设计和实现所有MVC部分,而Eclipse为您提供了一个API,可以为您完成大部分控制或渲染。因此,不能严格将Eclipse的MVC实现与Web或任何其他应用程序类型的MVC实现进行比较。

Eclipse JFace

Eclipse JFace使用内容提供者和标签提供者来实现MVC架构。JFace API包装标准(非平凡)的小部件,例如表和树,并实现结构化的内容提供程序和标签提供程序。您可以根据窗口小部件类型实现不同的内容提供程序。面向列表的查看器将实现结构化的查看器,其中内容以结构化(列出)的方式映射到小部件项目。

基类称为Viewer,它是结构化查看器的扩展。查看者充当小部件容器。内容提供者以结构化的方式获取数据;类似地,标签提供者获得相应的标签。JFace查看器实现检索此数据,设置相应的关联,并使用数据集更新用户界面(UI)组件。它还选择,过滤和排序。

如何实施JFace

EclipseViewViewer执行大多数JFace控制功能。Viewer,或MVC的View部分,还充当小部件容器;这是演示组件。

EclipseView实例化Viewers,内容提供者和标签提供者,它们充当模型,保存值对象,并将其设置Viewer为as inputElement

要创建View,请Viewer使用createPartControl()方法实例化一个清单1实例化了默认的树查看器;您还可以通过使用带有树对象作为参数的构造函数来自定义树并实例化树查看器。

清单1. ExampleView的CreatePartControl方法

1个
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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));
} ... }

在单独的类中,ImplementContentProvider是一个对象,该对象使用与您的查看器类型相对应的接口向视图提供数据。例如,您可以实现一个IStructuredContentProviderITreeContentProvider查看器。

通过在代码中实现以下方法之一,ContentProvider关联ViewerContentProvider

  • getElements(父对象)

  • getChildren(Object元素)

注意:JFace框架将调用这些方法。

清单2.创建一个自定义ContentProvider

1个
public class ExampleViewContentprovide implements ITreeContentProvide {

MVC体系结构通常涉及多个视图和单个数据源。当前,在Eclipse平台中,您只能将一个视图与单个模型关联。但是,您也可以创建多个视图,这些视图可以使用适配器视图来访问相同的数据。只需inputChanged()ContentProvider类中包括一个方法只要Viewer有了新的输入集,它就会使用inputChanged()方法通知ContentProviderinputChanged()方法接受aViewer作为输入参数,因此多个视图可以使用单个ContentProvider

清单3.对不同的查看器使用inputChanged方法

1个
2
3
4
5
6
7
8
9
/** * 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方法初始化布局

1个
2
3
4
public void createPartControl(Composite parent) {
ExampleEditLayout _layout = new
     ExampleEditLayout(parent,SWT.NONE,FieldMode.Read,new ExampleViewContentProvider());
         }

创建表单和布局

基本布局类定义了全局方法和不同表单应用程序使用的声明。在这里注册了一些充当回调机制的容器事件。

清单5.布局的CreateControl方法

1个
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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并赋予内容提供者读写能力。清单6FieldLayout类中使用Factory模式创建了一个

清单6.使用Field类创建文本对象

1个
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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中实现方法

1个
2
3
4
5
6
7
8
9
10
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并填充控件的表单

1个
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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/library/wa-eclipsemvc/index.html

其他参考:

https://stackoverflow.com/questions/19663017/java-implementing-mvc-with-swt

https://softwareengineering.stackexchange.com/questions/203384/implementing-mvc-pattern-in-swt-application

https://flylib.com/books/en/1.70.1/swt_jface_mechanisms.html

https://www.careerride.com/MVC-framework-within-JFace.aspx


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。