What is the Advanced Flex Table?

Advanced Flex Table is a basic class of all the grids. It extends standard GWT FlexTable widget and adds the following functionality:

  • thead tag support
  • browser independednt verticall scrolling of table content

You can use this widget directly for your own purposes as well as you usaully use FlexTable. Here is sample of AdnvacedFlexTable functionality.

AdvancedFlexTable table = new AdvancedFlexTable();

// create headers and put them in the thead tag
table.setHeaderWidget(0,new Label("First Name"));
table.setHeaderWidget(1,new Label("Surname"));

// enable verticall scrolling
table.enableVerticalScrolling(true);

This sample create a new table with two columns and enables vertical scrolling of table content. The main feature of the scrolling is that it keeps headers fixed and scrolls just body rows.

[top]


What is the Editable Grid?

Editable Grid is an extension of the Advanced Flex Table. It allows cells editing. Clicking on a cell a user will be able to change its content. It also supports entered values validation.

Editable model = new EditableGridDataModel(null);

// create a new grid panel
GridPanel panel = new GridPanel();

// create a new editable grid and put it into the panel
EditableGrid grid = panel.createEditableGrid (
   new String[]{"First Name","Surname"},
   new Class[]{LabelCell.class, LabelCell.class},
    null
);
grid.setModel(model);

It's a good practise to create a new editable grid using the Grid Panel, because in this case grid initialization is much simpler. The panel also provides grid managemnet controls like Grid Toolbar. Note that creating a new editable grid you must specify a list of grid cells. Grid cells define how the data will be displayed in a cell, whether it's editable and what specific event it can produce. Each cell class should implement the org.gwt.advanced.client.ui.widget.cell.GridCell interface. Here is a list of supported cells.

Cell Type Description
LabelCell This is a simple read only textual cell. It is applicable for any String values.
TextBoxCell This is an editable textual cell. It is applicable for any String values.
BooleanCell This is a checkbox cell. It is applicable for Boolean values.
DateCell This is a date picker cell. It's applicable for Date values.
ShortCell This is a numeric cell. It's applicable for Short values.
IntegerCell This is a numeric cell. It's applicable for Integer and Short values.
LongCell This is a numberic cell. It's applicable for Long, Integer and Short values.
FloatCell This is a numeric cell. It's applicable for Float, Integer and Short  values.
DoubleCell This is a numeric cell. It's applicable for Double, Float, Long, Integer and Short values.
ImageCell This cell diaplays the GWT Image widget.
ListCell This cell displays the GWT ListBox widget. Note that it doesn't get arrays or lists!  ListBox instances can be used only.
HeaderCellImpl This is a header cell widget. Do not use it directly.
ExpandableCell This cell wraps original cell widget and shows  expanded / collapsed state image. It's required by the Hierarchical Grid. Do notuse it directly.
ComboBoxCell This cell displays a ComboBox widget. It provides the same functionality as ListCell, but uses ComboBox instances instead of LisBoxes.

You can also develop your own cell. Editable Grid supports Editable and LazyLoadable data models and doesn't support Hierarchical and Tree models.

[top]


What is the Hierarchical Grid?

Hierarchical Grid extends the Editable Grid and supports all the same features. Additionaly it allows you to display subgrids related to particular cells of the main grid.

Editable hierarchicalModel = new HierarchicalGridDataModel(null);

// create a new grid panel
GridPanel panel = new GridPanel();

// create a new editable grid and put it into the panel
HierarchicalGrid grid = (HierarchicalGrid) panel.createEditableGrid (
   new String[]{"Department","Number of Employees"},
   new Class[]{LabelCell.class, IntegerCell.class},
   null
);

// add a grid panel factory to the second column
grid.addGridPanelFactory(
   1,new GridPanelFactory() {
       public GridPanel create(GridDataModel model) {
           GridPanel panel = new GridPanel();
           // create a new grid here
           return panel;
       }

       public GridDataModel create(int parentRow, GridDataModel parentModel) {
           return new EditableGridDataModel(new Object[0][0]);
       }
   }
);
grid.setModel(hierarchicalModel);
// display all
panel.display();

Hierarchical Grid initialization is similar to the previous one. Moreover the Grid Panel automatically detects what type of grid that must be created by the model type. The difference is that for hierarchical grids you must specify a grid panel factory and map it to a particular column. In this case for each cell of this column will be an expandable widget created.

The panel factory must implement the org.gwt.advanced.client.ui.GridPanelFactory interface. This factory contains two methods. One of them should create a data model for the subgrid, another one should create a grid panel inself. Note that the grid panel of the subgrid must be initialized in this method but NOT displayed. Hierarchical Grid will do it automatically.

The sample above shows how to create editable data grid model, but you can modify it and create hierarchical data models as well. Hierarchical Grid supports Editable, Hierarchical and LazyLoadable models.

[top]


What is the Tree Grid?

Tree Grid is a widget that displays tree-like data models. You can use as well as the Editable Grid. The difference will be in data models. Tree Grid requires any implementation of the Composite interface. If the model you're specifieng doesn't implement this interface the grid won't work properly.

The library provides the standard implementation of the interface - TreeGridDataModel. How to create an instance of this class and initilize it read this answer.

[top]


What is the Grid Panel, Toolbar and Pager?

As you saw in previous samples (1 and 2) it's recommended to use the Grid Panel widget to create grids. This widget is a facade object for all other grids and grid related widgets. Here is a list of such components:

  • Grid Toolbar. This component is a toolbarthat provides several buttons to control the grid placed in the panel. Pressing thebuttons a user can add new rows, remove rows, clear the grid and save results (force data synchronization).
  • Pager. This is a widget that allows change current page of data displayed in the grid.
  • different grids

By default the grid panel has two pagers (top and bottom) and one toolbar (top). But you can switch them off and / or display the widgets in other positions.

GridPanel panel = new GridPanel();

panel.setTopPagerVisible(false);// switch off the top pager
panel.setBottomPagerVisible(true);// switch on the bottom pager
panel.setTopToolbarVisible(false);// switch off the top toolbar
panel.setBottomToolbarVisible(true);// switch on the bottom toolbar

panel.setInvisibleColumn(0,true);// set the first column invisible
panel.setSortableColumn(1,false);// make the second column non-soirtable
panel.setReadonlyColumn(2,true);// make the third column read only

As the grid panel is a facade widget you can also use some methods which directly change grid options: columns visibility, sortable columns, read only columns, etc

[top]


What is the Master-Detail Panel?

Master-Detail Panel allows displaying a structure of grids, where content of the detail grid depends on a selected row of the master grid. Sometimes it may be good alternative to the hierarchical grids in those cases when the master grid contains plain entities, i.e. each cell is a simple object and there are no cell dependencies.

This panel extends GWT FlexTable and automatically detects where each of adding grid panels should be placed on the screen. Actually it works like Swing grid layout manager.

MasterDetailPanel panel = new MasterDetailPanel();

GridPanel masterPanel =new GridPanel();
panel.addGridPanel(masterPanel,null,"Departments");

// initialize the master grid here

masterPanel.display();

GridPanel detailPanel = new GridPanel();
panel.addGridPanel(detailPanel, masterPanel,"Employees");

// initialize the detail grid here

detailPanel.display();

// apply styles
panel.display();

Note that you should define a callback handler of the detail grid properly to be sure it displays the correct set of rows. When a user selects any row of the master grid, this handler will be automatically invoked to synchronize data. The last line of the listing is required only to apply CSS since the Master-Detail Panel is able to display nested grid panels dynamically.

[top]


What is the Locking Panel?

The locking panel is a widget that you'll never use directly. It extends GWT pop-up panel and is used by the grid panel for locking. It prevents any mouse clicks on the screen before the grid panel unlock it.

[top]


How to make a grid load data from the server side?

Just use callback handlers. Any callback handler can load data using GWT RPC, but don't forget about locking mechanism. Ideally you should lock the grid before RPC request sending and unlock in somewhere in the AsyncCallbackHandler.onSuccess() method. This rule is mandatory, otheriwise data synchronization may work wrong.

For details see also: What is the Lazy Data Model?, How does data synchronization work?, How to develop a custom callback handler?

[top]


How to enable client side paging and sorting?

There is no way to force it. Editable Grid (and child classes) automatically detects client side sorting and paging by type of the data model you choose. If it's NOT LazyLoadable, then client side srting and paging will be enabled.

[top]


How to develop a custom cell?

Custom cell development consists of three steps:

  • Cell widget creation
  • Cell factory creation
  • Set the cell factory to a grid

By default the grids use the org.gwt.advanced.client.ui.widget.cell.DefaultGridCellFactory to instantiate cells. If you want to make them use you own cell widgets you must define custom cell factory as well. Extend the default factory or directly implement the org.gwt.advanced.client.ui.widget.cell.GridCellFactory interface and set it for the grid using the EditableGrid.setGridCellfactory() method. The next sample illustrates how custom grid cell widget can be developed.

public class MyCell extends AbstractCell {
   private Button button=new Button("Sample");

   protected Widget createActive() {
       button.setEnabled(true);// enabled and avaliable when the cell is active
       return button;
   }

   protected Widget createInactive() {
       button.setEnabled(false);// disabled before a user clicks the cell
       return button;
   }

   public void setFocus(boolean focus) {
     // do nothing
}

   public Object getNewValue() {
       return button;
   }
}

MyCell is a cell that contains a button widget. By default the button is disabled. But when a user clicks a cell and make it active, the button is enabled.

[top]


What is a grid renderer?

Grid renderer is an entity that performs grid headers and content rendering fucntionality. There are default renderers specified for the grids but you can change default implenetations with your own ones. Note that all the grid renderers must implement the same interface: org.gwt.advanced.client.ui.GridRenderer. You can inherit it directly but the best practise is to extend one of defaul implemntations like it's shown below:

public class MyGridRenderer extends DefaultGridRenderer {
   public MyGridRenderer(EditableGrid grid) {
       super(grid);
   }

   public void drawHeaders(Object[] headers) {
       //draw simple labels
       for (int i =0; i < headers.length; i++) {
            Object header = headers[i];
            getGrid().setHeaderWidget(i,new Label(String.valueOf(header)));
       }
   }
}

This sample renders simple headers represented as standard label widgets. Use the EditableGrid.setGridRenderer() method to assign this sample implemntation to your grid.

[top]


How to implement server side rendering?

Its' very easy. Just write HTML code rendering component on server side (it may be JSP or any templating engine) and pass generated HTML to GWT client side via GWT RPC. Now when you have the generated HTML write the following class:

public class ServerSideContentRenderer extends DefaultGridRenderer {
   private String html;// HTML tbody content rendered on server side

   public ServerSideContentRenderer(EditableGrid grid, String html) {
       super(grid);
       this.html= html;
   }

   public void drawContent(GridDataModel model) {
       DOM.setInnerHTML(getTBodyElement(),html);
   }
}

Note if use at least one editable column you have to fill a data model with correct data, i.e. you need two copies of data: original and rendered as HTML. Now assign the new renderer to your grid using the EditableGrid.setGridRenderer() method.

[top]


Client side vs server side rendering. What is preferable?

Here is list of feature for both approaches. comparing you situation with the described below you can choose the most preferable solution.

Client side rendering:

  • Easy to develop. Actually it has already been developed by default.
  • Supported by all kinds of grids.
  • There is no data duplication described above.
  • Low perfomance due to JavaScript limitations.

Server side rendering:

  • To develop it you will have to implement your own HTML code generator on server side.
  • HierarchicalGrid won't support it automatically if you use expandable cells.
  • Data duplication required to support updatable columns.
  • High perfomance.

So if you need read only grid with large displayable pages the server side rendering approach is your choice. In other cases client side rendering is more preferable excepting application specific circumstances.

[top]


How to validate an entred cell value?

To validate a value of the cell you should implement the org.gwt.advanced.client.ui.EditCellListener interface and using the EditableGrid.addEditCellListener() method add this listener to a grid.

public class MyValidator implements EditCellListener {
   public boolean onStartEdit(GridCell cell) {
      return true;// if this method returns false, the cell will never be activated
  }

   public boolean onFinishEdit(GridCell cell, Object newValue) {
       // if the first column value is equal to "wrong", return false
       return cell.getColumn() !=0 || !"wrong".equals(newValue);
   }
}

This validator checks whether the new value of the first column is equal to "wrong" and if it's so returns false. In this case the grid restores the old value automatically and deactivates the cell. Note that onStartEdit() should return true in most cases otherwise the cell will never be activated and users can't edit the value.

[top]


My grid doesn't refresh content on page change / sorting / saving. What can I do?

Probably you use callback handlers and forgot about locking mechanism. Read the following answer: What is locking and why is locking mandatory if I use server side synchronization?

[top]


How to develop a custom grid panel factory?

Custom grid panel factories required only if you want to use hierarchical grids. The following sample shows how to create your own grid panel factory.

public class MyGridPanelFactory implements GridPanelFactory {
   public GridPanel create(GridDataModel model) {
       GridPanel panel =new GridPanel();

       // initialize the subgrid
       panel.createEditableGrid (
           new String[]{"First Name","Surname"},
           new Class[]{LabelCell.class, LabelCell.class},
           null
       ).setModel((Editable)model);

       return panel;
   }

   public GridDataModel create(int parentRow, GridDataModel parentModel) {
       // default initialization
       return new EditableGridDataModel(new Object[0][0]);
   }
}

See answer What is the Hierarchical Grid? to know how to use panel factories.

[top]


How to handle row selection?

If you want to do any action on row selection you should implement the org.gwt.advanced.client.ui.SelectRowListener interface and using the EditableGrid.addSelectRowListener() add it to the grid.

public class MyRowSelectionListener implements SelectRowListener {
   public void onSelect(EditableGrid grid,int row) {
        Window.alert("Row number " + row);
   }
}

This listener displays the alert window every time when a new row selected.

[top]


How to enable multiple row selection?

The EditableGrid and other subclasses support multiple row selection mode. To enable it you should invoke the EditableGrid.setMultiRowModeEnabled() method.

Using this mode you can choose more than one row if you press Shift or Ctrl button.

[top]


How to set default row selection?

Normally you can select any row using the setCurrentRow() method. But by default all the grids select the first row as soon as the grid rendered. Sometimes you may require another default cursor position. In this case it might be too late to use setCurrentRow(). Since version 1.4.0 you can invoke setDefaultSelectedRow() method before display().

[top]


How to make a column be read only?

Just use one the following methods:

  • GridPanel.setReadonlyColumn()
  • EditableGrid.setReadOnly()

[top]


How to make a column be sortable?

By default all the columns are sortable. But if you want to make some of them unsortable just invoke one the following methods:

  • GridPanel.setSortableColumn()
  • EditableGrid.setSortable()

[top]


How to make a cell expandable in the hierarchcal grid?

You can't do it directly. Instead you should add a custom grid panel factory to an appropriate column. See What is the Hierarchical Grid? and How to develop a custom grid panel factory? for details.

[top]


How many levels allowed in the hierarchical grid?

As many as you wish. But note that you ahve to use Hierarchical data models in subgrids. See What is the Hierarchical Grid? and How to develop a custom grid panel factory? for details.

[top]


Can the hierarchical grid use Editable (non-hierarchical) data models?

Yes. It supports all existent types of models.

[top]


Can the tree grid use Editable (non-tree) data models?

No. The problem is in totally different mechanisms of initializtion and rendering.

[top]


How to check grid content rendering progress, for instance to display a progress bar?

Just use the org.gwt.advanced.client.ui.GridRowDrawCallbackHandler interface. Extensions of this class can be passed to the grid and it will inform your handler about the progress. Note that this feature may make rendering slower. Use it only if you have to render large data sets. Consider the example below.

ProgressBar bar = new ProgressBar("Please wait...");

grid.setRowDrawHandler(bar);
bar.show();

ProgressBar is a hypotetic progress bar widget that can be used in your application. It's important to show it before you invoke the display() method. Otherwise control may ba catched by the grid and the progreess bar won't have a chance to be shown before rendering finished. The ProgressBar should implement the GridRowDrawCallbackHandler interface. This particular decision is applicable for this sample but you can implement your own handler which will change progress externally.

[top]


Are the grid columns resizable?

Yes. This feature is available by default. Just press left mouse button over the line between headers and holding it down move the mouse right or left. Note that to keep column resizability enabled you shouldn't specify grid and column sizes in percents and don't use setStyleName() and addStyleName() methods because they override any programmatic styles.

[top]


Do the grids support keyboard events?

Yes. The grids of this library are able to handle keyboard events via grid event managers. By default the following list of key codes is supported.

Operation Description Key Code Modifiers
Cell activation / deactivation (opening for edit / closing) Enter -
Move the cursor down Key Down -
Move the cursor right Key Right -
Move the cursor up Key Up -
Move the cursor left Key Left -
Move the cursor to the first cell of the page Home Shift
Move the cursor to the last cell of the page End Shift
Move the cursor to the first page Home -
Move the cursor to the last page End -
Open the next page PgDn -
Open the previous page PgUp -
Move the cursor to the next cell (tabbing like in Excel) Space Alt-Ctrl
Move the cursor to the previous cell (backward tabbing like in Excel) Space Shift-Alt-Ctrl

You can also specify your own key combinations but note that some browsers may use the same keys for other purposes. In this case you will have to disable this unexpected functionality programmatically.

[top]


What is a grid event manager? How to customize it?

Grid event manager is a program unit that handles all keyboard and mouse events of the grid. Each kind of grids has its own grid event manager implementation. So if the Editable Grid uses the DefaultGridEventManager the Hierarchical Grid handles events via the HierarchicalGridEventManager. Both implementations have one super interface: org.gwt.advanced.client.ui.GridEventManager You can supply your own manager implementing this interface. Conside the sample below:

public class MyGridEventManager extends DefaultGridEventManager {
   public MyGridEventManager(GridPanel panel) {
       super(panel);
   }

   public void dispatch(GridPanel panel,char keyCode,int modifiers) {
       if (keyCode == KEY_TAB)//move the cursor to the next cell on TAB pressing
           moveToNextCell();
       else
           super.dispatch(panel, keyCode, modifiers);
   }
}

This listing illustrates how to implement moving the cursor to the next cell on TAB key pressing. You can assign the manager to a grid using the EditableGrid.setGridEventmanager() method. Note that some key and combinations of keys may be used by particular browsers for other purposes. So you will have to disable browser specific functionality programmatically.

[top]


How to enable the paging feature for subtrees in the TreeGrid?

Use the TreeGridRow.setPagingEnabled() method.

[top]


How the grids update view on data change?

Every time you programmatically change data in the data model the EventMediator receives the EditableGridModelEvent. This event contains all required information regarding what was changed and how. According to these values the mediator invokes an appropriate protected methods of the grid.

[top]