How to make GWT Datagrid have its first column fixed and scroll horizontally and vertically

datagrid, gwt

Solution

I have implemented ScrolledGrid that freezes first column in DataGrid. You need to use it instead of DataGrid in order to make first column be frozen.

import com.google.gwt.dom.client.*;
import com.google.gwt.event.dom.client.ScrollEvent;
import com.google.gwt.event.dom.client.ScrollHandler;
import com.google.gwt.user.cellview.client.DataGrid;
import com.google.gwt.user.client.ui.HeaderPanel;
import com.google.gwt.user.client.ui.ScrollPanel;

/**
 *
 * @author Yuri Plaksyuk
 */
public class ScrolledGrid extends DataGrid {

    private final Text cssText;
    private boolean addedClass = false;
    private int currentScrollLeft = 0;

    public ScrolledGrid() {
        cssText = Document.get().createTextNode("");

        StyleElement styleElement = Document.get().createStyleElement();
        styleElement.setType("text/css");
        styleElement.appendChild(cssText);

        HeaderPanel headerPanel = (HeaderPanel) getWidget();
        headerPanel.getElement().insertFirst(styleElement);

        final ScrollPanel scrollPanel = (ScrollPanel) headerPanel.getContentWidget();
        scrollPanel.addScrollHandler(new ScrollHandler() {

            @Override
            public void onScroll(ScrollEvent event) {
                int scrollLeft = scrollPanel.getHorizontalScrollPosition();
                if (scrollLeft != currentScrollLeft) {
                    StringBuilder css = new StringBuilder();
                    if (scrollLeft > 0) {
                        css.append(".ScrolledGrid-frozen {");
                        css.append("background-color: inherit;");
                        css.append("}");

                        css.append(".ScrolledGrid-frozen div {");
                        css.append("position: absolute;");
                        css.append("left: ").append(scrollLeft).append("px;");
                        css.append("width: ").append(getColumnWidth(getColumn(0))).append(";");
                        css.append("padding-left: 1.3em;");
                        css.append("padding-right: 0.5em;");
                        css.append("margin-top: -0.7em;");
                        css.append("white-space: nowrap;");
                        css.append("background-color: inherit;");
                        css.append("}");
                    }
                    else
                        css.append(".ScrolledGrid-frozen { }");

                    css.append("th.ScrolledGrid-frozen { background-color: white; }");

                    cssText.setData(css.toString());


                    if (!addedClass) {
                        NodeList<TableRowElement> rows;
                        TableRowElement row;
                        TableCellElement cell;

                        rows = getTableHeadElement().getRows();
                        for (int i = 0; i < rows.getLength(); ++i) {
                            row = rows.getItem(i);
                            cell = row.getCells().getItem(0);
                            cell.setInnerHTML("<div>" + cell.getInnerHTML() + "</div>");
                            cell.addClassName("ScrolledGrid-frozen");
                        }

                        rows = getTableBodyElement().getRows();
                        for (int i = 0; i < rows.getLength(); ++i) {
                            row = rows.getItem(i);
                            cell = row.getCells().getItem(0);

                            cell.addClassName("ScrolledGrid-frozen");
                        }
                        addedClass = true;
                    }

                    currentScrollLeft = scrollLeft;
                }
            }
        });
    }
}

Unfortunately, some CSS values are hard-coded.

Problem

Currently GWT DataGrid header does this trick with a fixed header row during a vertical scroll. Is there a way to acheive the same on an entire (first) column?

Original source