5.6. 表格融合,DataGrid表体可以合并单元格

表格融合指的是,DataGrid表体单元格可以按照某种规则合并(一般是同值合并),从而体现行(列)数据之间的某种共有的关系。要使用融合表格,必须先给表格指定一个merged="true"的属性。

表格融合主要有2种使用方法:列融合和指定区域融合。这两种方法既可以单独使用,也可以一起配合使用。

列融合主要负责某一列里,将具有相同的元素值的多个小单元格合并成一个大的单元格,元素值不改变。这用到了DataGrid的mergedColumns属性,下面是一个例子

<w:dataGrid id="myDataGrid" paged="true" height="200" merged="true" var="p">
  <w:gridHeader>
    <w:gridHeaderCell label="label1" colspan="1" />
    <w:gridHeaderCell label="label2" colspan="1" />
    <w:gridHeaderCell label="label3" colspan="1" />
  </w:gridHeader>
  <w:outputColumn id="test1" value="#{p.a}" />
  <w:outputColumn id="test2" value="#{p.b}" />
  <w:outputColumn id="test3" value="#{p.c}" />
</w:dataGrid>

上面的代码定义了一个普通的表格,其中w:dataGrid的merged="true"属性指定了这个表格可以进行融合。将要融合的列由w:dataGrid的mergedColumns属性指定(由将要融合的列的id组成),可以在页面上用EL表达式来指定(如mergedColumns="#{mergeGridBean.mergedColumns}"),也可以在LiteBean中进行IoVC。下面是LiteBean的部分代码

    @Bind(id="myDataGrid",attribute="mergedColumns")
    private String[] mergedColumns = new String[] {"test1"};
    
    @DataModel
    private GridArray[] myDataGrid = new GridArray[] {
        new GridArray("1", "1", "1"), 
        new GridArray("2", "1", "2"),
        new GridArray("2", "3", "3"), 
        new GridArray("2", "5", "4"),
        new GridArray("2", "5", "5")
    };

从上面的代码说明了id为test1的那一列将会融合,GridArray是一个辅助类(标准的JavaBean,包含几个属性、一些getter/setter和构造函数),其对象代表表格的一行数据,它共有三个属性a、b、c。

从上面的代码容易看出,test1显示的是GridArray的a属性,而且test1这一列会融合,DataModel中a这一列第1行为1,第2~5行都是2,因此这一列的第2到5行单元格将会合并,效果如下图。

如果我们把LiteBean中的mergedColumns改为new String[] {"test2"}效果会怎么样呢?test2这一列显示是的GridArray的b属性,DataModel中这一列的第1~2行是1,第4~5行是5,因此效果会变成下图这样。

当表格中有不止一列的单元格需要融合,则遵循前面的列优先融合的规则。前面的列融合形成几个大单元格之后,每个大单元格占据的那几行数据组成一个小表格,后面的列要融合的话只能在小表格内部融合,不能跨表格融合。如果我们把LiteBean中的mergedColumns改为new String[] {"test1", "test2"}效果会变成下图这样。

因为mergedColumns中test1这一列有优先权,所以会优先对这一列进行合并,虽然test2那一列第1~2行数据是一样的,但是test2列融合的优先级低,所以并不会合并。如果我们把LiteBean中的mergedColumns改为new String[] {"test2", "test1"},让test2列有融合的优先权,效果就会变成下图这样。

指定区域融合可以让用户可以随意的指定哪些区域需要融合起来。这需要用到<w:dataGrid>的mergedInfos属性,页面代码如下:

<w:dataGrid id="myDataGrid" paged="true" height="200" merged="true" var="p">
  <w:gridHeader>
    <w:gridHeaderCell label="label1" colspan="1" />
    <w:gridHeaderCell label="label2" colspan="1" />
    <w:gridHeaderCell label="label3" colspan="1" />
  </w:gridHeader>
  <w:outputColumn id="test1" value="#{p.a}" />
  <w:outputColumn id="test2" value="#{p.b}" />
  <w:outputColumn id="test3" value="#{p.c}" />
</w:dataGrid>

<w:dataGrid>的merged属性依然设为true。后台代码如下:

    @Bind(id="myDataGrid",attribute="mergedInfos")
    private MergedInfo[] mergedInfos = new MergedInfo[]{ new MergedInfo(1, 1, 2, 2, "2") };
    
    @DataModel
    private GridArray[] myDataGrid = new GridArray[] {
        new GridArray("1", "1", "1"), 
        new GridArray("2", "1", "2"),
        new GridArray("2", "3", "3"), 
        new GridArray("2", "5", "4"),
        new GridArray("2", "5", "5")
    };

上面的代码同样用IoVC方式定义了让表格中某个区域进行融合的行为。MergedInfo是API里的一个类(标准的JavaBean),它的构造函数中,前4个参数定义了融合区域坐上角和右下角的行列坐标(表格中,第1行第1列的坐标是0,0),最后一个参数定义了在融合区域上显示的字符串。

上面的代码中,从第2行第2列(参数1,1表示第2行第2列而不是第1行第1列)到第3行第3列的4个单元格被融合成1个单元格,其内容是"2"。效果如下图。

当在表格中既定义了列融合,又定义了区域融合,情况会怎样呢?两者都会起作用,但最好不要让两个行为作用在共同的单元格上,这样表格会长成不可预知的形状。