网格

组件:gridcolumnscolumnrowsrow

Grid包含排列整齐的组件就像表格一样。在grid内,你可以声明columns,定义了header及column属性;还可以声明 rows,提供内容。

使用rows组件可以声明一套row,即为grid元素的子组件。在rows内可以为每一行添加row组件。你可以 在row元素内添加你想要的内容。每个子元素为指定行的一列。

类似的,columns是由columns组件声明的,其将作为grid的一个子组件。不同于row用于保留每行的内容,column声明了每列的通用属性,例如宽度和对齐方式,还有可选的headers,也就是标签或图像。

<grid>
   <columns>
      <column label="Type"/>
      <column label="Content"/>
   </columns>
   <rows>
      <row>
         <label value="File:"/>
         <textbox width="99%"/>
      </row>
      <row>
         <label value="Type:"/>
         <hbox>
            <listbox rows="1" mold="select">
               <listitem label="Java Files,(*.java)"/>
               <listitem label="All Files,(*.*)"/>
            </listbox>
            <button label="Browse..."/>
         </hbox>
      </row>
   </rows>
</grid>

滚动网格

当指定了height属性且没有足够的空间来显示数据时,grid会变为滚动的。

<grid width="500px" height="130px">
   <columns>
      <column label="Head 1"/>
      <column label="Head 2" align="center"/>
      <column label="Head 3" align="right"/>
   </columns>
   <rows>
      <row>
         <listbox mold="select">
            <listitem label="Faster"/>
            <listitem label="Fast"/>
            <listitem label="Average"/>
         </listbox>
         <datebox/>
         <textbox rows="2"/>
      </row>
      <row>
         <checkbox checked="true" label="Option 1"/>
         <checkbox label="Option 2"/>
         <radiogroup>
            <radio label="Apple"/>
            <radio label="Orange" checked="true"/>
            <radio label="Lemon"/>         </radiogroup>
      </row>
      <row>
         <checkbox checked="true" label="Option 1"/>
         <checkbox label="Option 2"/>
         <radiogroup orient="vertical">
            <radio label="Apple"/>
            <radio label="Orange" checked="true"/>
            <radio label="Lemon"/>
         </radiogroup>
      </row>
   </rows></grid>

可变列宽

如果你允许用户改变每列的宽度,可以将columnssizable属性的设为true。一旦允许用户进行此操作,用户可以通过拖动相邻列的边框来改变列宽,如下,

<window>
   <grid>
      <columns id="cs" sizable="true">
         <column label="AA"/>
         <column label="BB"/>
         <column label="CC"/>
      </columns>
      <rows>
         <row>
            <label value="AA01"/>
            <label value="BB01"/>
            <label value="CC01"/>
         </row>
         <row>
            <label value="AA01"/>
            <label value="BB01"/>
            <label value="CC01"/>
         </row>
         <row>
            <label value="AA01"/>
            <label value="BB01"/>
            <label value="CC01"/>
         </row>
      </rows>
   </grid>
   <checkbox label="sizeable" checked="true" onCheck="cs.sizeable = self.checked"/>
</window>

onColSize事件

一旦用户改变了列宽,onColSize事件及org.zkoss.zul.event.ColSizeEvent的一个实例会被送出。注意列宽是在onColSize事件被送出前被调整的。换言之,你可以忽略作为一个通知的事件。当然,你可以在事件监听器中做你想做的事。

分页网格

有两种方式在grid中处理较长的内容:滚动及分页。滚动可以由指定height属性来实现,就像在前面讨论的一样。分页可以通过将mold属性设为paging来实现的。一旦分页可用,grid会将内容分为几页并且在同一时间内只显示一页。如下所示,

<grid width="300px" mold="paging" pageSize="4">
   <columns>
      <column label="Left"/>
      <column label="Right"/>
   </columns>
   <rows>
      <row>
         <label value="Item 1.1"/><label value="Item 1.2"/>
      </row>
      <row>
         <label value="Item 2.1"/><label value="Item 2.2"/>
      </row>
      <row>
         <label value="Item 3.1"/><label value="Item 3.2"/>
      </row>
      <row>
         <label value="Item 4.1"/><label value="Item 4.2"/>
      </row>
      <row>
         <label value="Item 5.1"/><label value="Item 5.2"/>
      </row>
      <row>
         <label value="Item 6.1"/><label value="Item 6.2"/>
      </row>
      <row>
         <label value="Item 7.1"/><label value="Item 7.2"/>
      </row>
   </rows>
</grid>

一旦设置为分页模式,grid将会创建paging组件的一个实例作为其子组件。然后它将会关注分页( It then takes care of paging for the grid it belongs to)。

pageSize属性

一旦设置为分页模式,你可以通过pageSize属性指定每次的可见行数(也就是页面大小,page size)。默认为20。

paginal属性

如果你喜欢将paging组件置于不同的位置或你想使用同一个paging组件控制两个或更多的grid,可以明确指明paginal属性。注意:如果没有明确指明,即同于paging属性。

<vbox>
<paging id="pg" pageSize="4"/>
<hbox>
   <grid width="300px" mold="paging" paginal="${pg}">
      <columns>
         <column label="Left"/><column label="Right"/>
      </columns>
      <rows>
         <row>
            <label value="Item 1.1"/><label value="Item 1.2"/>
         </row>
         <row>
            <label value="Item 2.1"/><label value="Item 2.2"/>
         </row>
         <row>
            <label value="Item 3.1"/><label value="Item 3.2"/>
         </row>
         <row>
            <label value="Item 4.1"/><label value="Item 4.2"/>
         </row>
         <row>
            <label value="Item 5.1"/><label value="Item 5.2"/>
         </row>
         <row>
            <label value="Item 6.1"/><label value="Item 6.2"/>
         </row>
         <row>
            <label value="Item 7.1"/><label value="Item 7.2"/>
         </row>
      </rows>
   </grid>
   <grid width="300px" mold="paging" paginal="${pg}">
      <columns>
         <column label="Left"/><column label="Right"/>
      </columns>
      <rows>
         <row>
            <label value="Item A.1"/><label value="Item A.2"/>
         </row>
         <row>
            <label value="Item B.1"/><label value="Item B.2"/>
         </row>
         <row>
            <label value="Item C.1"/><label value="Item C.2"/>
         </row>
         <row>
            <label value="Item D.1"/><label value="Item D.2"/>
         </row>
         <row>
            <label value="Item E.1"/><label value="Item E.2"/>
         </row>
         <row>
            <label value="Item F.1"/><label value="Item F.2"/>
         </row>
      </rows>
   </grid>
</hbox></vbox>

paging属性

其为一个用来呈现paging子组件(自动创建来处理分页)只读属性。如果你通过paginal属性指派了额外的分页,它的值将为空。你很少会访问到此属性。相反,使用paginal属性。

OnPaging事件及方法

一旦用户点击了paging组件的分页数字,onPaging事件会被送至grid。onPaging方法会处理此事件。默情况下,此方法或使rows的内容无效,也就是刷新。

如果你想实现"(依要求创建)create-on-demand" 特性,你可以为grid的onPaging事件添加一个事件监听器。

grid.addEventListener(org.zkoss.zul.event.ZulEvents.ON_PAGING, new MyListener());

排序

grid支持直接的行排序。如果你想打开某一列的递增排序,可以为sortAscending属性指派一个java.util.Comparator实例。类似的,可以为sortDescending属性指派一个comparator来打开递减排序。

如下所示,首先得实现comparator 接口来比较grid的任意两行,然后将其实例指派给sortAscendingsortDescending属性。注意:compare方法由org.zkoss.zul.Row的实例调用。

<zk>
   <zscript>
      class MyRowComparator implements Comparator {
         public MyRowComparator(boolean ascending) {
         ...
         }
         public int compare(Object o1, Object o2) {
            Row r1 = (Row)o1, r2 = (Row)o2;
            ....
         }
      }
      Comparator asc = new MyRowComparator(true);
      Comparator dsc = new MyRowComparator(false);
   </zscript>
   <grid>
      <columns>
         <column sortAscending="${asc}" sortDescending="${dsc}"/>
...

sortDirection属性

sortDirection属性用来控制是否在客户端显示一个图标,以显示特定列的排列顺序。如果每行元素在添加到grid前即已排好序,则需要明确设定这个属性。

<column sortDirection="ascending"/>

然后,只要你为相应的列指定比较器(comparator),grid会自动维护此属性。

onSort事件

当你为某一列至少指定了一个比较器(comparator),则若用户点击了此列onSort事件会被送至服务器。column组件实现了监听器,基于指定的比较器(comparator)自动为行(rows)排序。

若你倾向于手工处理,可以为onSort事件将你自己的监听器添加到指定列。为了阻止默认的监听器调用sort方法,你必须调用stopPropagation方法来阻止事件被接收。另外,你可以重定义sort方法,见下文。

sort方法

sort方法是onSort事件监听器的最底层实现。如果你使用Java代码为行排序,则这会非常有用。例如,你或许必须在添加行(假定未排序)后调用此方法。

Row row = new Row();
row.setParent(rows);
row.appendChild(...);
...
if (!"natural".column.getSortDirection())
   column.sort("ascending".equals(column.getSortDirection()));

默认排序算法为快速排序(quick-sort)(org.zkoss.zk.ui.Components类的sort方法)。你可以使用自己的实现来重定义此方法。

注:sort方法会检测排序顺序(通过调用getSortDirection)。仅在排序顺序不同时sort才会为行排序。若想强制排序,可按如下方式,

column.setSortDirection("natural");
sort(myorder);

等价于:

sort(myorder, true);

实况数据

就像listbox,gird支持live data一样。使用实况数据,开发人员可以将数据从视图分离。换言之,开发人员仅需实现rg.zkoss.zul.ListModel接口类提供数据。而非直接操作grid。好处有以下两点,

  • 易于使用不同的视图来显示相同的数据。

  • grid仅在其可见时才会将数据送至客户端。在数据量巨大时可以减少大量的网络流量(network traffic)。

使用实况数据需要经过三步,

  1. ListModel形式准备好数据。ZK有一个称为org.zkoss.zul.SimpleListModel的具体实现,用于显示一个数组对象。

  2. 实现org.zkoss.zul.RowRenderer接口用于将数据行送至grid。

    • 这是可选的。若为指定,默认的渲染器(renderer)会启,并将数据送至第一列。

    • 你可以实现不同的渲染器(renderer),这样可以在不同的视图中显示相同的数据。

  3. 在model属性中指定数据,并且可以选择在rowRenderer属性指定渲染器(renderer)。

在下面的例子中,我们准备了一个称为strset的列表模型,通过grid的model属性为其指定此值。然后,grid会处理剩下的工作。

<window title="Live Grid" border="normal">
   <zscript>
      String[] data = new String[30];
      for(int j=0; j &lt; data.length; ++j) {
         data[j] = "option "+j;
      }
      ListModel strset = new SimpleListModel(data);
   </zscript>
   <grid width="100px" height="100px" model="${strset}">
      <columns>
         <column label="options"/>
      </columns>
   </grid></window>

实况数据的排序

如果你允许用户为提供实况数据的grid排序,则必须要实现org.zkoss.zul.ListModelorg.zkoss.zul.ListModelExt接口。

class MyListModel implements ListModel, ListModelExt {
   public void sort(Comparator cmpr, boolean ascending) {
      //do the real sorting
      //notify the grid (or listbox) that data is changed by use of ListDataEvent
   }
}

当用户请求grid排序时,grid将会调的用ListModelExtsort方法来为数据排序。换言之,排序 是由列表模型(list mode)完成的,而不是grid。

排序完成之后,列表模型会调用org.zkoss.zul.event.ListDataListener实例(通过addListDataListener方法注册在grid)的onChange方法来通知grid。在大多数情况下,所有的数据通常会变化,所以列表模型通常会发送下列事件:

new ListDataEvent(this, ListDataEvent.CONTENTS_CHANGED, -1, -1) 

辅助表头

除了columns,你可以使用auxheadauxheader组件指定辅助表头,如下。

<grid>
   <auxhead>
      <auxheader label="H1'07" colspan="6"/>
      <auxheader label="H2'07" colspan="6"/>
   </auxhead>
   <auxhead>
      <auxheader label="Q1" colspan="3"/>
      <auxheader label="Q2" colspan="3"/>
      <auxheader label="Q3" colspan="3"/>
      <auxheader label="Q4" colspan="3"/>
   </auxhead>
   <columns>
      <column label="Jan"/><column label="Feb"/><column label="Mar"/>
      <column label="Apr"/><column label="May"/><column label="Jun"/>
      <column label="Jul"/><column label="Aug"/><column label="Sep"/>
      <column label="Oct"/><column label="Nov"/><column label="Dec"/>
   </columns>
   <rows>
      <row>
      <label value="1,000"/><label value="1,100"/><label value="1,200"/>
      <label value="1,300"/><label value="1,400"/><label value="1,500"/>
      <label value="1,600"/><label value="1,700"/><label value="1,800"/>
      <label value="1,900"/><label value="2,000"/><label value="2,100"/>
      </row>
   </rows>
</grid>

辅助表头支持colspanrowsspan属性,而列表头(column header)并不支持。但是,就像名字暗示的那样,辅助表头必须和column一起使用。

不同于column/columns仅可以为grid所使用,auhead/auxheader可以被用于grid,listbox 和 tree

特殊属性

spans属性

为一个整数列表,以逗号分隔,用于就控制是否将一个元素(cell)跨越几列。列表中的第一个数字表示第一个元素跨越的列数,第二个数字表示第二个元素跨越的列数,依次类推。若省略数字,则为1。

例如,

<grid>
   <columns>
      <column label="Left" align="left"/><column label="Center" align="center"/>
      <column label="Right" align="right"/><column label="Column 4"/>
      <column label="Column 5"/><column label="Column 6"/>
   </columns>
   <rows>
      <row>
         <label value="Item A.1"/><label value="Item A.2"/>
         <label value="Item A.3"/><label value="Item A.4"/>
         <label value="Item A.5"/><label value="Item A.6"/>
      </row>
      <row spans="1,2,2">
         <label value="Item B.1"/><label value="Item B.2"/>
         <label value="Item B.4"/><label value="Item B.6"/>
      </row>
      <row spans="3">
         <label value="Item C.1"/><label value="Item C.4"/>
         <label value="Item C.5"/><label value="Item C.6"/>
      </row>
      <row spans=",,2,2">
         <label value="Item D.1"/><label value="Item D.2"/>
         label value="Item D.3"/><label value="Item D.5"/>
      </row>
   </rows>
</grid>