Grid

From Documentation

Grid

Employment/Purpose

Components: grid, columns, column, rows and row.

A grid contains components that are aligned in rows like tables. Inside a grid, you declare two things, the columns, that define the header and column attributes, and the rows, that provide the content. To declare a set of rows, use the rows component, which should be a child element of grid. Inside that you should add row components, which are used for each row. Inside the row element, you should place the content that you want inside that row. Each child is a column of the specific row. Similarly, the columns are declared with the columns component, which should be placed as a child element of the grid. Unlike row is used to hold the content of each row, column declares the common attributes of each column, such as the width and alignment, and and optional headers, i.e., label and/or image.

Example

ZKComRef Grid Example.png


 <window title="Grid Demo" border="normal" width="360px">
     <zscript>
     class Comp implements Comparator {
         private boolean _asc;
         public Comp(boolean asc) {
             _asc = asc;
         }
         public int compare(Object o1, Object o2) {
             String s1 = o1.getChildren().get(0).getValue(),
                 s2 = o2.getChildren().get(0).getValue();
             int v = s1.compareTo(s2);
             return _asc ? v: -v;
         }
     }
     Comp asc = new Comp(true), dsc = new Comp(false);
     </zscript>
     <grid>
         <columns sizable="true">
             <column label="Type" sortAscending="&#36;{asc}" sortDescending="&#36;{dsc}" width="50px"/>
             <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>
             <row>
                 <label value="Options:"/>
                 <textbox rows="3" width="99%"/>
             </row>
         </rows>
     </grid>
 </window>

Grid onAfterRender.png

<zk>
	<zscript><![CDATA[
		ListModelList lm = new ListModelList(Arrays.asList(new String[] { "David",
				"Thomas", "Steven" }));
	]]></zscript>
	
	<grid model="${lm}" width="300px"
		onAfterRender='gridCount.setValue("row count: "+self.getRows().getChildren().size()+"");' />
	<label id="gridCount" />
</zk>

Paging

The listbox and grid components support the paging intrinsically, so you don't need to specify a paging component explicitly as above unless you want to have different visual layout or to control multiple listbox and gridcontrols with one paging component.

Grids with Paging

There are two ways to handle large content in a grid, scrolling and paging. Scrolling is enabled by setting the height attribute as discussed in the previous section. Paging is enabled by setting the mold attribute to paging. Once paging is enabled, the grid separates the content into several pages and displays one page at a time as depicted below.

ZKComRef Grid Paging.png

 
<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>

Once the paging mold is set, the grid creates an instance of the paging component as a child of the grid and the paging component in turn handles the grid』s paging. Therefore, the number of the grid』s children includes the paging component. Also, if you remove all children of the grid, the paging is also removed.

The PageSize Property

Having set the paging mold, you can specify how many rows are visible at a time (i.e., the page size) by setting the pageSize attribute to a numeric value. By default, it is 20.

The Paginal Property

If you prefer to place the paging component in a different location or you want to control two or more grids with the same paging component, you can assign the paginal attribute explicitly. Note: if it is not set explicitly, it is the same as the paging property.

ZKComRef Grid Paginal.png

 
<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>

The Paging Property

It is a read-only attribute representing the child paging component that is created automatically. It is null if you assign external paging via the paginal attribute. You rarely need to access this attribute as it is generally better to use the paginal attribute.

The onPaging Event and Method

Once a user clicks the page number of the paging component, an onPaging event is sent the grid. It is then processed by the onPaging method. By default, the method invalidates, i.e., redraws, the content of rows.

If you want to implement "create-on-demand" feature, you can add a event listener to the grid for the onPaging event. The line below demonstrates how to add an EventListener.

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


Autopaging

[Since 5.0.2]

When using the paging mold and vflex, you could also turn on autopaging (Grid.setAutopaging(boolean)) such that the page size will be adjusted automatically based on the available space.

For example,

<grid id="listbox" autopaging="true" mold="paging" vflex="true">
    <columns>
        <column label="column1"/>
    </columns>
    <rows>
        <row forEach="${items}">
         ${each}
        </row>
    </rows>
</grid>

Grid autopageSize.png

Sort

Sorting

Grids support the direct sorting of rows. To enable ascending order sorting for a particular column, you need to assign a java.util.Comparator instance to the sortAscending attribute of the column. Similarly, you assign a comparator to the sortDescending property to enable the descending order.

As illustrated below, you first implement a comparator that compares any two rows of the grid, and then assign its instances to the sortAscending and/or sortDescending attributes. Notice: the compare method is passed two Row instances.

<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}"/>
 ...

The onSort Event

When you assign at least one comparator to a column, an onSort event is sent to the server if user clicks on it. The column component implements a listener to automatically sort rows based on the assigned comparator.

If you prefer to handle this manually, you can add your own listener to the column for the onSort event. To prevent the default listener to invoking the sort method, you have to call the stopPropagation method for the event being received. Alternatively, you can override the sort method, see below.


The sortDirection Property

The sortDirection property controls whether to show an icon to indicate the order of a particular column. If rows are sorted before being added to the grid, you should set this property explicitly.

<column sortDirection="ascending"/>

It is then maintained automatically by the grid as long as you assign the comparators to the corresponding column.

The sort Method

The sort method is the underlying implementation of the default onSort event listener. It is also useful if you want to sort the rows using Java code. For example, you might have to call this method after adding rows (assuming they not in the proper order).

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

The default sorting algorithm is quick-sort (by use of the sort method from the Components class). You can override it with your own implementation.

Note: the sort method checks the sort direction (by calling getSortDirection). It sorts the rows only if the sort direction is different. To enforce the sorting, do as follows.

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

The above code is equivalent to the following.

sort(myorder, true);

Update: see more about sorting Multiple Field Sorting on Listbox.

Live Data

Like list boxes, grids support live data. With live data, developers are able to separate the data from the view. In other words, developers only need to provide the data by implementing the ListModel interface, rather than manipulating the grid directly. The benefits are twofold.

  • It is easier to use different views to show the same set of data.
  • The grid sends the data to the client only if it is visible. It saves a lot of network traffic if the amount of data is large.

There are three steps to make use of live data.

1 Prepare the data in the form of a ListModel. ZK has a concrete implementation called SimpleListModel for representing an array of objects. 2 Implement the RowRenderer interface for rendering a row of data into the grid.

    • This is optional. If it is not specified the default renderer is used to render the data into the first column.
    • You can implement different renderers for representing the same data in different views.

3 Set the data in the model attribute and, optionally, the renderer in the rowRenderer attribute.

In the following example, we prepared a list model called strset, assign it to a grid using the model attribute. Then, the grid will do the rest.

ZKComRef Grid LiveData.png

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

Sorting with Live Data

If you allow users to sort a grid with live data, you have to implement the interface, ListModelExt, in addition to the ListModel.

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
	}
}

When a user wants to sort the grid, the grid will invoke the sort method of ListModelExt to sort the data. In other words, the sorting is done by the list model, rather than the grid.

After sorting, the list model will notify the grid by invoking the onChange method of the grid's registered ListDataListener instances. These are registered by the addListDataListener method. In most cases, all the data is changed, so the list model usually sends the following event:

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

Properties

Scrollable Grid

ZKComRef Grid ScrollableGrid.png

A grid can be scrollable if you specify the height attribute and there is not enough space to display all data.

<grid span="true" sizedByContent="true" 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>

Auxiliary Headers

In addition to columns, you can specify auxiliary headers with the auxhead and auxheader components as follows.

ZKComRef Grid AuxiliaryHeaders.png

<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>

The auxiliary headers support the colspan and rowsspan attributes that the column header don't. However, as its』 name suggests, the auxiliary headers must be placed within a column.

Unlike column/columns, which can only be used with grid, auhead/auxheader can be used with grid, listbox and tree.

SizedByContent

By default, the widths of columns have to be specified explicitly, or it will be split equally among columns regardless what content they might have. If you want to have the minimal width (that fit the content), you could specify hflex="min" at the column (not the grid).

However, the grid has a special mode called sized-by-content (Grid.setSizedByContent(boolean)). By specifying it to true, the column width will be adjusted automatically. However, it is controlled by the browser, so have have no 100% control of it. For example, if an user resized a column, the final width might not be exactly the same as what he resized.

In general, we suggest to specify hflex in column, rather than specifying sizedByContent at grid for much more predictable result.

Span

By default, when sizedByContent is true, column only take required space.

ZKComRef Grid Nospan.png

If wanna to span the width of the columns to occupy the whole grid, you could specify true to this attribute

ZKComRef Grid Span.png

	<grid sizedByContent="true" span="true" width="800px">
		<columns>
			<column label="Time Message" />
			<column label="Level" />
			<column label="Source " />
			<column label="Message" />
		</columns>
		<rows>
			<row>
				<label value="6/28/10 4:19:18 PM" />
				<label value="Info, long content.........................." />
				<label value="Server" />
				<label value="Merging recovery point 52 created 20 6/27/10 10 :11 PM" />
			</row>
		</rows>
	</grid>

Sizable

If you allow users to resize the width of your columns, you can set the sizable attribute of your columns as true. Once allowed, users can resize the widths of columns by dragging the border between adjacent column components.

<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>

Auto Fitting Columns

When you want to resize a column of a Grid or Listbox, all you now need to do is double click the column when the mouse is over where the columns meet and the column will automatically resize to fit its contents. To enable this functionality Grid's columns need the attribute sizable="true". In other words, all sizable column provides the auto-fitting functionality.

[Since 5.0.0]

The onColSize Event

Once a user resizes the width, the onColSize event is sent with an instance of ColSizeEvent. Notice that the column's width is adjusted before the onColSize event is sent. In other words, the event serves as a notification that you can ignore. Of course, you can do whatever you want in the event listener.

Spans

It is a list of comma separated integers, controlling whether to span a cell over several columns. The first number in the list denotes the number of columns the first cell shall span. The second number denotes the number of columns the second cell will span and so on. If a number is omitted, 1 is assumed.

For example,

<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>

Master Detail

Grid supports master-detail concepts which enables developers to add more information on each row. For example,

ZKComRef Grid Detail.png

	<rows>
		<row>
			<detail open="true">
				<hlayout>
					<image sclass="myimg" width="100px" height="100px"
						src="/img/item1.jpg" />
					// omitted...
				</hlayout>
			</detail>

Columns Menu

For example,

ZKComRef Grid Columns Menu.png

<zk>
	<grid>
		<columns menupopup="auto">
			<column label="Author" sort="auto"/>
			<column label="Title" sort="auto"/>
			<column label="Publisher" sort="auto"/>
			<column label="Hardcover" sort="auto"/>
		</columns>
		// omitted...
	</grid>
</zk>

Cell Component

In ZK5, we have introduced a new component named Cell which can be embedded into a Grid or Box (Hbox and Vbox) to fully control the layout and the style. You can now use the rowspan or the colspan property to layout your Grid, for example a content cell can now cross over multiple rows. The code below demonstrates how to do this:

<row>
    <cell sclass="years" rowspan="12">
        ...
    </cell>
</row>
[Since 5.0.0]

Group Component

Both Grid, and Listbox support Grouping concept, it enables developers to display data in an advanced way. Moreover, live data are also supported in Grouping Grid, and Listbox with the GroupsModel interface..

ZKComRef Grid Grouping.png

<zk>
	<zscript>
	import org.zkoss.zkdemo.userguide.*;
	Comparator asc = new RowLabelComparator(true),
		dsc = new RowLabelComparator(false);
	</zscript>
	<grid>
		<columns sizable="true">
			<column label="Brand" sortAscending="&#36;{asc}" sortDescending="&#36;{dsc}"/>
			<column label="Processor Type" width="150px"/>
			<column label="Memory (RAM)" width="120px"/>
			<column label="Price"  width="100px"/>
			<column label="Hard Drive Capacity" width="150px"/>
		</columns>
		<rows>
			<group label="Dell"/>
			<row>
				<label style="padding-left:15px" value="Dell E4500 2.2GHz"/>
				<label value="Intel Core 2 Duo"/>
				<label value="2GB RAM"/>
				<label value="$261.00" style="color:green"/>
				<label value="500GB"/>
			</row>
			<row>
				<label style="padding-left:15px" value="XP-Pro Slim Dell-Inspiron-530-s"/>
				<label value="Intel Core 2 Duo"/>
				<label value="2GB RAM"/>
				<label value="$498.93" style="color:green"/>
				<label value="500GB"/>				
			</row>
			<row>
				<label style="padding-left:15px" value="Dell P4 3.2 GHz"/>
				<label value="Intel Pentium 4"/>
				<label value="4GB RAM"/>
				<label value="$377.99" style="color:green"/>
				<label value="500GB"/>				
			</row>
			<group label="Compaq"/>
			<row>
				<label style="padding-left:15px" value="Compaq SR5113WM"/>
				<label value="Intel Core Duo"/>
				<label value="1GB RAM"/>
				<label value="$279.00" style="color:green"/>
				<label value="160GB"/>				
			</row>
			<row>
				<label style="padding-left:15px" value="Compaq HP XW4200"/>
				<label value="Intel Pentium 4"/>
				<label value="4GB RAM"/>
				<label value="$980" style="color:green"/>
				<label value="500GB"/>				
			</row>
			<groupfoot spans="5">
				<label value="This a summary about Compaq Desktop PCs"/>
			</groupfoot>
		</rows>
	</grid>
</zk>
*Available in ZK PE and EE only

For more information, please take a look at these smalltalks,

Or refer to Group component directly.

Frozen Component

In ZK 5 you are now able to freeze columns within a Grid and Listbox. This mirrors functionality seen within Excel and makes data in these components easier to read, interpret and handle.

The following code demonstrates how to freeze a column within a Grid:

<grid>
	<frozen style="background: #dfded8" columns="3">
		...
	</frozen>
</grid>
[Since 5.0.0]

Supported Events

Name
Event Type
onAfterRender
Event: Event

Notifies one that the model's data has been rendered.

onRender
Event: RenderEvent

Denotes user has scrolled to the unloaded area.

onInnerWidth
Event: Event

Denotes user has resized the column of this grid then the inner width of this grid has been changed.

onDataLoading
Event: DataLoadingEvent

Notifies one that the unload data has been rendered.

onChangePageSize
Event: Event

Notifies the paging size has been changed when the autopaging enable and user changed the size of the content.

Supported Molds

Available molds of a component are defined in lang.xml embedded in zul.jar.

Name
Snapshot
default
Grid mold default.png
paging
Grid mold paging.png

Supported Children

* Columns,  Rows,  Foot

Use Cases

Version Description Example Location
     

Version History

Last Update : 2011/03/08


Version Date Content
5.0.2 May 2010 Support the autopaging
5.0.4 July 2010 Support onAfterRender event
5.0.5 October 2010 The span property was introduced to span the columns to occupy the whole grid.



Last Update : 2011/03/08

Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.