Sunday, February 10, 2008

GWT - FlexTable with frozen header

DataGrids displaying a huge set of data with header for each column would be better usable with its header row frozen.
Plain HTML tables, with frozen header are very simple to create.

  1. Create THEAD and TBODY elements.
  2. For TBODY element's style set overflow: auto or scroll;
  3. Set fixed size for the TBODY element
In GWT, a table created using either using Grid or FlexTable, creates only TBODY element and no THEAD element.
So to render a table with frozen header, in GWT we'll have to extend either Grid or FlexTable with a THEAD element and a few getter and setter methods for accessing the THEAD columns.



package name.aanand.magix.client;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Widget;


public class DataGrid extends FlexTable {

private Element head;
private Element headerTr;

public DataGrid() {
super();
head = DOM.createTHead();
headerTr = DOM.createTR();
DOM.insertChild(this.getElement(), head, 0);
DOM.insertChild(head, headerTr, 0);
Element tBody = getBodyElement();
DOM.setElementAttribute(tBody, "style", "overflow:auto;text-align: left;");
DOM.setElementAttribute(head, "style", "text-align: left;");

}

public void setHeight(String height) {
DOM.setElementAttribute(getBodyElement(), "height", height);
}

public void setHeader(int column,String text){
prepareHeader(column);
if (text != null) {
DOM.setInnerText(DOM.getChild(headerTr, column), text);
}
}

private void prepareHeader(int column) {
if (column < 0) {
throw new IndexOutOfBoundsException(
"Cannot create a column with a negative index: " + column);
}
int cellCount = DOM.getChildCount(headerTr);
int required = column + 1 - cellCount;
if (required > 0) {
addCells(head, 0, required);
}
}


public void setHeaderWidget(int column, Widget widget) {
prepareHeader(column);
if (widget != null) {
widget.removeFromParent();
// Physical attach.
DOM.appendChild(DOM.getChild(headerTr, column), widget.getElement());

adopt(widget);
}
}

private native void addCells(Element table, int row, int num)/*-{
var rowElem = table.rows[row];
for(var i = 0; i < num; i++){
var cell = $doc.createElement("td");
rowElem.appendChild(cell);
}
}-*/;