Advanced Flex Table is a basic class of all the grids. It extends standard GWT FlexTable widget and adds the following functionality:
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.
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.
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.
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.
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:
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
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.
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.
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?
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.
Custom cell development consists of three steps:
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.
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.
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.
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:
Server side rendering:
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.
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.
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?
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.
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.
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.
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().
Just use one the following methods:
By default all the columns are sortable. But if you want to make some of them unsortable just invoke one the following methods:
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.
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.
Yes. It supports all existent types of models.
No. The problem is in totally different mechanisms of initializtion and rendering.
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.
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.
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.
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.
Use the TreeGridRow.setPagingEnabled() method.
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.