媒体与新闻

媒体报道与出版物

Eclipse华丽转身之控件表格工厂

转载本文需注明出处:微信公众号EAWorld,违者必究。


书归正传,接演前文~(Eclipse插件开发之简单控件封装——那些年冗长的裹脚布)上回我们介绍了对象编辑器的封装,对象编辑器之外就是控件工厂的封装,而在众多类型的控件工厂中,想必大家最关心的,莫过于对槽点满满的原生Tree/Table的封装。这回我们便好好来说道说道~

在此之前,我们还是要简单介绍一下控件工厂。

控件工厂

根据不同的UI需求,我们框架封装了许多控件工厂来完成灵活的应用需求。

IControlFactory控件工厂,因为有一些控件是运行时才会被创建的,而且要创建的控件也有可能不确定,所以提供一个这样的工厂用来创建控件,下图为它的类结构图。


AbstractControlFactory是IControlFactory的基类。这个基类在实现IValueContaier的同时还实现了IValueChangeListener和IValidateListener这样主要是通过Proxy的模式,只在内部的控件中添加自己作为Listener。

表格工厂

我们知道,无论是SWT的Table还是JFace的TableViewer/TreeViewer,都不能满。我们广泛需求,比如修改数据。而在我们开发过程中,表格往往是个非常普遍多次使用的控件,所以这里就要引入我们的表格工厂的封装了。那么,我们先简述以下表格工厂相关的几个概念(构建器、数据转换器、备忘录)。

表格构建器
Builder分为KTableBuilder和KTreeBuilder,其实他们是使用了第三方表格组件KTable来进行构造表格。

先来说一下KTable表格工厂的构建器KTableBuilder,下图为Builder的关系类图;


当需要使用一个KTableBuilder的时候我们一般直接new一个对象出来,可以看下它三种构造函数中带参数的一种;
public KTableBuilder(KTable r_KTable, IKTableColumn[] r_Columns, ITableDataProvider r_TableDataProvider, IAdaptable r_Adaptable) {
    this.setTableColumns(r_Columns);
    this.setDataProvider(r_TableDataProvider);
    this.build(r_KTable,r_Adaptable);
  }
其中的ITableDataProvider就是数据提供者接口,为表格提供数据和排序。然后表格构建器通过doBuild方法来绘制表格。
数据转换器
Translator数据转换器,可以将数据转换成复杂控件使用的数据,如表格使用的列表数据;
举一个例子来理解什么是Translator,例如Stuido的逻辑流文件(*.bizx文件),用文本编辑器开打后可以看到图形化编辑器中的图元的信息都是使用XML规范来描述的,比如一个运算逻辑图元属性如下图;

则图片上表格中的值与模型对象之间的关系,这样就不难理解Translator数据转换器需要做的事情了,接下来看下它的类图;

其中AbstractKTableFactory# doCreateControl方法,在创建UI控件的时候调用了getTranslator方法返回的就是实现IObjectTranslator接口的子类;
protected Control doCreateControl(Composite r_Parent, UIDefinition r_UIDefinition) {
………………………………………………………………………
    IObjectTranslator t_Translator = this.getTranslator();
    IKTableColumn[] t_Columns = this.getColumns();
    for (int i = 0; i < t_Columns.length; i++) {
      if (t_Columns[i] instanceof AbstractTableColumn) {
        AbstractTableColumn t_Column = (AbstractTableColumn) t_Columns[i];
        t_Column.setIntrospector(t_Translator.getIntrospector());
//这里会为每一个column设置一个数据访问器
      }
    }
………………………………………………………………………
    return createActionComposite(r_Parent, r_UIDefinition.isView());
  }

看下IObjectTranslator接口中定义的方法;

同样formeTree和toTree方法,适用于KTreeBuilder创建出来的UI控件上表格数据的保存和回显;


fromTable方法在AbstractKTableFactory中的save方法中被调用,一般用于UI界面上编写好数据,类似按保存按钮,或者向导中“确定”或者“完成”按钮时候调用,用于把表格中填写的数据存在一个数据备忘录IMemento中。
toTable方法在这个UI界面被构造的时候方法中,new一个数据备忘录IMemento(后面的章节会讲到)的时候被调用,用于回显上一次填写的数据。
备忘录
IMemento提供一个数据备份和恢复的接口,可以用来备份数据和恢复数据.它与IStore非常相似,但是为了便于理解,使用Memento名字。可以参考Memento模式,下图为实现IMemento接口的子类,都可以根据自己控件的特性来备份恢复数据;

接口中就定义了2个方法,分别为backup备份数据,restore恢复数据,我们先可以来看一下TableMemento中的方法;
protected List doBackup(String r_Type, Object r_Model) {
    if (null==this.objectTranslator) {
      return new ArrayList();
    } else{    
      return this.objectTranslator.toTable(r_Type, r_Model);
    }
  }
在Translator章节中我们讲述了toTable方法,它是翻译成一个可以用于表格数据的列表,在AbstractKtableFactory中构造UI的方法中(doCreateControl)方法中我们会新建一个TableMemento的实例对象。在构造TableMemento实例的时候就会调用构造函数中的backup方法来保存UI界面中控件的值。
那接口中restore恢复数据何时被调用呢?可以看下图,例如我们在数据集编辑器中空白处点击右键出现的菜单如下图;


ICommand是用来提供Redo和Undo的接口,SimpleCommand则是ICommand的实现类,实现类中的redo和undo方法都会调用IMemento实现类的restore方法调用后来恢复数据。


基本概念说完了,我们看下具体的表格工厂:KTable、KTree、Table。


KTable表格工厂


AbstractKtableFactory用来支持表格控件的创建。


getCloumns方法:返回一个IKTableColumn []的数组,必须由子类来实现,IKTableColumn是用来支持Ktable的表格列,一般只需要构造一个KPropertyTableColumn(该数据列用来通过property来访问对象)就可以了。
getActionProvider方法:返回的IKTableActionProvider是控件上的一些Action操作,通常可以通过创建DefaultKTableActionProvider对象来实现。子类可以重写这个方法来构造自己的Action来进行对表中的数据进行操作。
getTranslator方法:返回数据数据转换器,通常为自己自定义的数据转换类
KTree表格工厂



AbstractKTreeFactory和AbstractKTableFacotory区别不大。通过UI界面可以看到区别,“参数”和“返回值”就好比一个树的跟节点root,而参数param1和参数param2为“参数”root的子节点。
AbstractKTreeFactory中是使用KTreeBuilder来构造表格的,KTreeBuilde中有一个重要的属性ITreeNode,下图是它的类关系图:


DefaultTreeNode实现了ITreeNode的接口并且继承了AbstractPropertyAwareElement(能够监控属性改变的类,当属性改变时,会发出相应的信息通知所有的监听者),KTreeBuilder类里面有一个方法叫做setRootNode()可以设置树的根节点,而ITreeNode的子类都可以构造自己的节点然后通过setParent()的方法设置父类节点,或者调用add()方法来添加自己的孩子节点,其中重要的是DefaultTreeNode的setUserObject()方法,它是用来为每个节点set一个对象的方法。我们来看一个示例(逻辑流出入参的数据转换器BusinessLogicTranslator):

Table表格工厂


AbstractTableFactory和AbstractKTableFactory基本很相像,看下一它的类关系图如下:


在AbstractTableFactory中构造表格的TableBuilder可以从上类图中看出来,其实是就是封装了eclipse自身的TableViewer,而不是AbstractKTableFactory中封装的KTable,这是两者之间本质的区别。


IKTableColumn



说完了表格工厂以后,我们回头再来看之前表格工厂里提到的一个方法getCloumns(),在这个方法中返回的是IKTableColumn []的数组。上文图中的表格列都是最基本的输入框也就是KPropertyTableColumn,除此之外还有哪些Column的封装呢?


通过此图列举的类不难看出,表格Column的常用封装都可以满足了,无论是下拉框、复选框、还是带有图片的Column。那么下一篇我们就来详细说一下,表格工厂Column的封装,除此之外还有更为复杂的Column封装(如图),以及其他几个控件工厂的介绍。

  - end -  


关于作者:leaf淼,普元高级软件工程师,善于Studio插件的开发与设计,目前负责EOS/BPS Studio产品开发,曾参与浦发银行BPM流程产品开发、太平洋保险集团微服务平台开发等。



关于EAWorld:微服务,DevOps,数据治理,移动架构原创技术分享。长按二维码关注!

咨询