Oops Null Pointer

Java programming related

Category Archives: GXT

Book review: ExtGWT Rich Internet Application Cookbook

ExtGWT cookbook

Overview:

The ExtGWT Cookbook from Packt Publishing covers the GXT UI framework version 2 (currently at 2.2.6) as well as a quick overview of key features of GWT and some ideas on building robust UI frameworks. While a good knowledge of GWT itself is recommended, this book could be used a basic primer of some of the required concepts.

I think it’s important to bring up that the version of GXT this book covers is now a major revision behind the latest: GXT 3.0.

A lot has changed in GXT 3.0 and thus some of the detail in the Cookbook is not applicable to projects using this version. Some examples are:

  • The GXT data model (BeanModel) is now replaced by POJOs (using GWT AutoBeans)
  • Wigets can now use UIBinder
  • GXT Event listeners are replaced by GWT handlers
  • The flash charts are replaced by a new JavaScript based chart package

So with that in mind, who is this book useful for? The GXT widgets are relatively unchanged and this book covers the set-up and options of nearly all the widgets in detail and is still helpful from this aspect. The book also covers some useful ideas for building robust UI frameworks; it explores the idea of an “action” that different views can share, each which their own set of supported options. For those who have existing investments in applications using GXT 2 or are just starting projects will find this book a great companion – I wish I had this book during the creation of my current application as it would of helped clarify some of the quirks in GXT and replace the rather lack lustre GXT documentation. It also would of added some depth in the architecture, reducing repetition and linking related components.

Layout:

The ExtGWT Cookbook’s layout is code heavy – in a good way. Each recipe follows the format of a description of a feature, a “how do do it” code section and a detailed “how it works” line by line breakdown of the code. In this way you are rarely left wondering what a line of code does and any GXT quirks are normally highlighted and explained.

The progression of the examples builds well through each chapter and in the same way the chapters tend to naturally flow on from one another, so the book can be read linearly, but each chapter is self contained enough that you can jump into a recipe with little reference to other sections.

The main documentation that GXT provides is the API and a set of examples with code. While better than nothing, they often are not enough to cover real life scenarios or they leave important options out. The ExtGWT Cookbook has more examples with a focus on building practical applications, and importantly the examples are detailed and backed by a comprehensive description.

I felt the detail and relevance was typically compelling enough to encourage reading through whole chapters. Nearly ever chapter covered a new aspect or feature that I hadn’t previously been aware of, making reading this book worthwhile.

Chapters:

The first three chapters cover the basic elements of panels, windows, tabs and “click-ware” (buttons, toolbars and menus). The section on tabs shows real world experience in the example which toggles the tab strip based on the number of tabs. The last recipe of chatper 3 “Bind a single action to several click-wares” introduces a useful pattern to relate an underlying action or behaviour to different representations that is elaborated and expanded in Chapter 11 in the recipe “A novel UI with MVP, actions and a bus”.

The next four chapters cover GXT specific layouts, trees and grids with enough thoroughness to provide a good head start in using these components.

Chapter 8 covers the GXT templates which allow the modification of views within components with easy access to model data properties. This was a topic that I found GXT’s own documentation was particularly unhelpful, while this chapter succinctly covered with several handy examples.

The built in charts are well covered in Chapter 9, although few would find this flash based package very useful (especially for mobile devices). The last recipe “Drawing on a canvas” hints at alternatives, but for detailed charts look to GXT 3 or an external library.

The chapters “Drag-and-drop”  (chapter 10) and “Theming” (chapter 12) adequately explain these topics and the appendices provide thoughtful coverage of topics that GWT developers need to know.

I found the “Advanced Tips” chapter (11) the most useful and insightful as it covered important architectural concepts for larger applications (MVP, History, working with persistence frameworks). Having gone through the pain of building similar patterns before they were more commonly discussed for GWT projects, I like the way this chapter helps lay the foundations of testable and robust GWT based software. The working server push recipe was also stimulates thoughts on building more interactive applications.

Summary:

In all the ExtGWT Cookbook is a very detailed and comprehensive overview of GXT 2.x. It inspired me to read the whole thing cover to cover and I only really didn’t learn something from the charts chapter as we have moved to Highcharts (and GXT has moved to a new JavaScript based charting framework in GXT 3).

There are some aspects of GXT’s layout system that were (for me) difficult to deal with that are not covered in this book – in particular deeply nested layouts and using components in resizable windows (say a grid in a portlet in a resizeable window). The GXT documentation avoided complicated layouts and the cookbook’s layouts are typically not too complicated either. This book is aimed at the beginner to intermediate as it lacks some depth in relation to constructing large / complicated GXT based applications, but it still has enough detail to learn some useful tips from.

I’d look forward to a GXT 3 version by the same authors, especially if it covered some more advanced patterns.

ExtGWT Cookbook Review in progress

I’m in the process of reviewing a GXT book called ExtGWT Rich Internet Application Cookbook.

Hopefully I’ll pick up a few tips on the way. It will be interesting to compare it to a book a did a technical review for around a year ago: Ext GWT 2.0 Beginners Guide.

Upgrade GWT 2.0.4 to GWT 2.4.0 with GXT 2.2.5

I just upgraded from GWT 2.0.4 to GWT to 2.4.0 and here are the jars I had to change:

Run time dependencies (WEB_INF/lib):

  • updated gwt-servlet.jar to 2.4.0 version
  • updated GXT.jar (2.2.5) had to be a version compiled for GWT 2.2 and above (previous I used the 2 version)
  • updated gwt-log-26.2 to gwt-log-3.1.6.jar
  • updated guice-2.0.jar to guice-3.0.jar
  • added guice-assistedinject-3.0.jar
  • removed gwt-java-math-1.0.9.jar (andremoved the reference from the module (gwt.xml) file
Build time dependencies:
  • updated all the GWT jars
  • updated gin-1.0.jar to gin-1.5.jar (post GWT 2.2 version)
  • added javax.inject.jar that comes with guice-3.0 (new)

GXT Hover BorderLayout

I created a GXT Borderlayout that will hover out a collapsed panel (as a popup) and hover it back in when you mouse out.

There is also a hook to allow you to collapse and expand the popup panel from the BorderLayout. In my case I collapse the popup when windows are activated so they don’t cover over the popup panel.

I can’t quite get the mouse out to always close the popup – if another window is overlapping the popup and you mouse into it the popup will not close. I only respond to mouse out’s that are outside the bounds of the panel (as many elements in the panel fire mouse out events). I was also collapsing the popup of it was no longer the front most component, but this means you can’t open popup menus from the panel without closing the popup (as they become the front most panel). Let me know if you have any improvements.

Here’s the HoverBorderLayout

/**
 * Copyright 2011 Calibre Financial Technology
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
import com.extjs.gxt.ui.client.Style.LayoutRegion;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.widget.BoxComponent;
import com.extjs.gxt.ui.client.widget.CollapsePanel;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.ComponentHelper;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.layout.BorderLayout;
import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;

/**
 * Border layout that supports "hovering" of collapsed regions - mouse over to toggle popup, and close popup on mouse out.
 *
 * @author cpritchett
 */
public class HoverBorderLayoutGXT extends BorderLayout {
    public static final int STANDARD_COLLAPSED_WIDTH = 24;
    public static final int MIN_COLLAPSED_WIDTH = 2;

    private boolean hoverEnabled = true;
    private int collapsedWidth = MIN_COLLAPSED_WIDTH;
    private boolean showCollapseTool = false;

    public HoverBorderLayoutGXT() {}

    public HoverBorderLayoutGXT(boolean hoverEnabled) {
        this.hoverEnabled = hoverEnabled;
        if (!hoverEnabled) {
            collapsedWidth = STANDARD_COLLAPSED_WIDTH;
        }
    }

    public HoverBorderLayoutGXT(int collapsedWidth) {
        this.collapsedWidth = collapsedWidth;
    }

    public HoverBorderLayoutGXT(boolean hoverEnabled, int collapsedWidth, boolean showCollapseTool) {
        this.hoverEnabled = hoverEnabled;
        this.collapsedWidth = collapsedWidth;
        this.showCollapseTool = showCollapseTool;
    }

    // As onExpandClick is private in GXT 2.2.4 use JSNI to break encapsulation until this is fixed in 2.2.5.
    private native void onExpandClickWrapper(CollapsePanel cp) /*-{
        this.@com.extjs.gxt.ui.client.widget.layout.BorderLayout::onExpandClick(Lcom/extjs/gxt/ui/client/widget/CollapsePanel;)(cp);
    }-*/;

    @Override
    protected CollapsePanel createCollapsePanel(ContentPanel panel, BorderLayoutData data) {
        CollapsePanel cp;
        if (hoverEnabled) {
            cp = new HoverCollapsePanelGXT(panel, data, showCollapseTool) {
                protected void onExpandButton(BaseEvent be) {
                    if (isExpanded()) {
                        setExpanded(false);
                    }
                    onExpandClickWrapper(this);
                }
            };
        }
        else {
            cp = new CollapsePanel(panel, data) {
                protected void onExpandButton(BaseEvent be) {
                    if (isExpanded()) {
                        setExpanded(false);
                    }
                    onExpandClickWrapper(this);
                }
            };
        }

        BorderLayoutData collapseData = new BorderLayoutData(data.getRegion());
        collapseData.setSize(collapsedWidth);
        collapseData.setMargins(data.getMargins());
        ComponentHelper.setLayoutData(cp, collapseData);
        cp.setData("panel", panel);
        panel.setData("collapse", cp);
        return cp;
    }

    // As getRegionWidget is private in GXT 2.2.4 use JSNI to break encapsulation until this is fixed in 2.2.5.
    private native BoxComponent getRegionWidgetWrapper(LayoutRegion region) /*-{
        return this.@com.extjs.gxt.ui.client.widget.layout.BorderLayout::getRegionWidget(Lcom/extjs/gxt/ui/client/Style$LayoutRegion;)(region);
    }-*/;

    public void setPopupExpanded(LayoutRegion region, boolean expanded)  {
        Component c = getRegionWidgetWrapper(region);
        CollapsePanel cp = null;
        if (c != null && c instanceof CollapsePanel)  {
           cp = ((CollapsePanel)c);
        }
        else if (c != null && c instanceof ContentPanel) {
            cp = (CollapsePanel) ((ContentPanel)c).getData("collapse");
        }

        if (cp != null) {
            if (expanded == false && cp instanceof HoverCollapsePanelGXT) {
                ((HoverCollapsePanelGXT)cp).forceHide();
            }
            else {
                cp.setExpanded(expanded);
            }
        }
    }
}

And here is the supporting classes – the HoverCollapsePanel

/**
 * Copyright 2011 Calibre Financial Technology
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.widget.CollapsePanel;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.layout.BorderLayoutData;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;

/**
 * In collapsed mode this supports the hiding and showing of the popup panel when hovering (mouse over / out of the
 * collapse panel and of the popup panel).
 *
 * @author cpritchett
 */
public class HoverCollapsePanelGXT extends CollapsePanel {
    // Tracks if the mouse is currently over the panel to ensure the toggle behaves correctly
    private boolean over = false;
    private boolean showHeader = true;

    /**
     * Creates a new hover supporting collapse panel
     *
     * @param panel the parent content panel
     * @param data the border layout data
     * @param showHeader Show header with expand tool. Set to false when panel size is too small for expand tool.
     */
    public HoverCollapsePanelGXT(ContentPanel panel, BorderLayoutData data, boolean showHeader) {
        super(panel, data);
        this.showHeader = showHeader;

        // Replace the standard Popup with a hover Popup
        popup = new HoverAutoHidePopupGXT()  {
            // Disable auto hide as we want to support clicks in the panel with hiding
            @Override
            protected boolean onAutoHide(Event event) {
                return false;
            }

            @Override
            protected void onMouseOut(ComponentEvent ce) {
                setExpanded(false);

                // On Popup mouseout clear the over flag unless mouseout was to this panel
                // (as the pointer is still "over" this component and we don't want to trigger another expand
                if (!HoverCollapsePanelGXT.this.el().getBounds().contains(ce.getXY())){
                    over = false;
                }
            };
        };
    }

    /**
     * Hides the popup and resets the over flag - call this when responding externals events that hide the navigator
     * (like a window activation). Resetting the over flag allows the next mouse over to respond (trigger an expand)
     */
    public void forceHide() {
        setExpanded(false);
        over = false;
    }

    @Override
    protected void onRender(Element target, int index) {
        super.onRender(target, index);

        // Ignore auto hide when clicking on this panel as the onComponentEvent will handle this.
        popup.getIgnoreList().add(this.getElement());

        if (!showHeader) {
            el().selectNode(".x-panel-header").hide();
        }
    }

    @Override
    public void onComponentEvent(ComponentEvent ce) {
        super.onComponentEvent(ce);

        // As mouseout / mouseover events are triggered multiple times in the header section,
        // store when the mouse really leaves this panel (the X and Y are outside theh bounds)
        boolean within = el().getBounds().contains(ce.getXY());
        boolean withinPopup = popup.isRendered() ? popup.el().getBounds().contains(ce.getXY()) : false;

        if (ce.getType().getEventCode() == Event.ONMOUSEOUT && !within && !withinPopup) {
            over = false;
            setExpanded(false);
        }

        if (ce.getType().getEventCode() == Event.ONMOUSEOVER && !over) {
            setExpanded(!isExpanded());
        }

        // Once the first mouseover is detected prevent other mouseovers from triggering expands
        if (ce.getType().getEventCode() == Event.ONMOUSEOVER && !over) {
            over = true;
        }
    }
}

and the HoverAutoHidePopup

/**
 * Copyright 2011 Calibre Financial Technology
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
import com.extjs.gxt.ui.client.event.ComponentEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.widget.Popup;

/**
 * A Popup that hides itself on hover - on a normal mouse out (when the event is fired out side the bounds of the Popup)
 * @author cpritchett
 */
public class HoverAutoHidePopupGXT extends Popup {
    protected void onMouseOut(@SuppressWarnings("unused") ComponentEvent ce) {
        hide();
    }

    public HoverAutoHidePopupGXT() {
        addListener(Events.OnMouseOut, new Listener() {
            public void handleEvent(ComponentEvent be) {
                // Hide popup then mouse moves out of bounds
                if (!HoverAutoHidePopupGXT.this.el().getBounds().contains(be.getXY())) {
                    onMouseOut(be);
                }
            }
        });
    }
}

GXT: BorderLayout starting with a collapsed region

Calling collapse on a BorderLayout region before it has been rendered doesn’t work. One suggestion was to add a deferred command to collapse the region. I found this was “flashing” the panel (showing and then hiding it) and also that when you pop out a collapsed panel (clicking on the collapsed section) the popup was empty as panel was still effectively collapsed. Instead I used a once only AfterLayout event listener:

layoutContainer.addListener(Events.AfterLayout, new Listener<ComponentEvent>() {
  public void handleEvent(ComponentEvent be) {
    borderLayout.collapse(LayoutRegion.WEST);
    be.getComponent().removeListener(Events.AfterLayout, this);
  }
});

Using this method some child components may have trouble rendering inside the collapsed panel. One such component is a TreePanel – if you add it and then call expandAll() it will throw a JavaScriptException, caused by the parent of the collapsed panel being null.
com.google.gwt.core.client.JavaScriptException: (TypeError): this.appendChild is not a function

To counter this I added a once only Attach event listener to the panel that will be collapsed:

myContentPanel.addListener(Events.Attach, new Listener<ComponentEvent>() {
  public void handleEvent(ComponentEvent ce) {
    myTreePanel.expandAll();
    // Remove this listener - expand only once
    ce.getComponent().removeListener(Events.Attach, this);
  }
});

GXT Enums, ComboBoxes and i18n

If you want to have a ComboBox that uses enums with i18n you can use a SimpleComboBox and use the enums toString() method to return the GWT i18n constants.

As I posted on the GXT forums, I don’t want to use toString() as I want the enum to still work on the server side (say during debugging).

Instead I have a getLabel() method and want the GXT ComboBox to call that. Here’s the code:

It does the following:

  • Convert the value in the ComboBox with a property editor to call getLabel()
  • Convert the values in the list with a ModelProcessor to call getLabel() and Template
  • The Enum

    public enum Condition {
      New,
      Used,
      Damaged
    
      public String getLabel()
      {
          // get i18n with a GWT create call save via a ConstantsWithLookup
      }
    }
    

    The ComboBox that uses Condition enum (with a getLabel() method for i18n)

    final SimpleComboBox<Condition> combo = new SimpleComboBox<Condition>();
    combo.setFieldLabel("Condition");
    combo.setName("condition");
    combo.add(Arrays.asList(Condition.values()));        
    combo.setEditable(false);
    combo.setAllowBlank(false);
    combo.setTriggerAction(TriggerAction.ALL);
    combo.setSimpleValue(Condition.NEW);
    

    The standard enum field binding:

    FieldBinding binding = new FieldBinding(combo, "condition") 
    {
        @SuppressWarnings("unchecked")
        @Override
        protected Object onConvertFieldValue(Object value) {
            return ((SimpleComboValue<Condition>)value).getValue();
        }
    
        @Override
        protected Object onConvertModelValue(Object value) {
            return combo.findModel((Condition)value);
        }
    };
    formBinding.addFieldBinding(binding);
    

    The rest (pretty ugly but it works)

    // Replace the text in the box with the enums label
    ListModelPropertyEditor<SimpleComboValue<Condition>> propEditor = 
        new ListModelPropertyEditor<SimpleComboValue<Condition>>()
        {
             public String getStringValue(SimpleComboValue<Condition> value) {
                 return value.getValue().getLabel();
             }
        };
    
    propEditor.setDisplayProperty("label");
    combo.setPropertyEditor(propEditor);
            
    // Replace the text in the list with the enums labels
    combo.getView().setModelProcessor(new ModelProcessor<SimpleComboValue<Condition>>() 
    {
        public SimpleComboValue<Condition> prepareData(SimpleComboValue<Condition> model) 
        {
            model.set("label", model.getValue().getLabel());
            return model;
        }
    });
            
    // Use label property in list as SimpleComboBox displayProperty "value" is used by default
    String html = "<tpl for=\".\"><div role=\"listitem\" class=\"" + combo.getListStyle() + "-item\">{" + "label" + "}</div></tpl>";
    combo.setTemplate(html);
    

    If all used enums implemented a “Labelable” (or Internationalisable?) interface that required the getLabel() method then this code could be reused for different enums.

    I’m using GXT 2.2.3 and GWT 2.0.4.

    GXT Charts cutting off the y-axis labels

    I was having issues with GXT charts deeply embedded in a hierarchy (chart -> ContentPanel -> Portlet -> Portal -> TabPanel -> Window) where the y axis labels where truncated for long strings.

    Oringinally I was adding spaces to the labels but causes OFC to add about 10-15 extra steps when using a bar chart will all values less than zero.
    So instead I add the chart, set the chart model, remove the chart, then add it again before laying out the panel.

    Actually this is a bug in the OFC source. Here is the explanation and the fix.

    You need to patch and recompile the swf used for the charts – and below I have provided the way to do it and attached the fixed open-flash-chart.swf file itself

    This bug in OFC 2 is mentioned in a few other places:here and here

    Here are the details of the issue and the fix:

    GXT uses a patched version of OFC2: “2 Ichor Patched by DZ”.
    This version has a bug that YAxis labels > 1,000,000 get cut of. If you resize the container of the chart then the labels get fixed.

    The latest version of OFC (trunk) is missing some DZ patches (e.g. tooltips show if value is “”) and also potentially not the full font range for unicode.

    The GXT version of DZ’s OFC is [B]not[/B] the same as the source code of this version from DZ’s website. The version from his site has another bug – the tooltips do not disappear on mouse out.

    Here is how to build a version that fixes the tooltip problem and the truncation issue

    Building from source: (See also this link)

    Download FlashDevelop – install

    • best location is C:\OFC\FlashDevelop otherwise you will have to edit the path in FullFont.xml and PartialFont.xml in the \obj fir of DZ’s OFC source

    Get and install flex sdk 3

    • Get Flex sdk v3
    • Unzip flex sdk
    • Add the bin flex bin dir to your path
    • Copy msvcr71.dllto bin dir of flex

    Get source code for DZ’s OFChere

    Fix bugs!

    • main.as – Move the line this.set_the_stage() to above the this.find_data() line
    • tooltip.as – The hide method is broken – either uncomment the tween line or manually add a call to hideAway
    • edit the build.bat file and change XAxisLabels-NoUnicodeRange.as and XAxisLabels-UnicodeRange.as to use underscores instead of dashes
    • edit the build.bat file and REM out the line that copies the SWF to a xampp dir

    Compile and deploy

    • cd to the open-flash-chart main dir (has the main.as file)
    • from the cmd line run build.bat
    • Rename the open-flash-chart-full-embedded-font.swf to open-flash-chart.swf
    • Copy into the war\lib\gxt\charts dir replacing the existing version

    Clear you browser cache or else the new swf will not be picked up.

    For a link to the bug report and the swf file see here
    Email me / comment if you need more info.

    Fixing font height to match GXT

    GXT (2.1.1) uses fixed font heights in Internet Explorer. While there may be (possibly valid) readability arguments against this, that the way it is. Unfortunately when I added a Text component next to a ComboBox in a HorizontalPanel (as I’m not in a form), the text in the Text widget resizes while the text in the ComboBox doesn’t. Looks a bit ridiculous in hosted mode and IE6-8.

    The key to fixing the font size and having the text match the ComboBox item text is the following CSS (required lines are commented):

    font-size:12px; /*Set the font size to match combo item */
    line-height:20px ; /*Set the line-height to match combo item */
    

    The whole css is here:

    .combo-text-label {
    font-family:tahoma,arial,helvetica,sans-serif;
    font-size:12px; /*Set the font size to match combo item */
    font-size-adjust:none;
    font-style:normal;
    font-variant:normal;
    font-weight:normal;
    line-height:20px ; /*Set the line-height to match combo item */
    }
    

    Apply this as the sole style to the Text component and the font size no longer grows as if it is changed in IE:

    HorizontalPanel hp = new HorizontalPanel();
    hp.setSpacing(6);
    hp.setBorders(true);
    hp.setVerticalAlign(VerticalAlignment.MIDDLE);
    
    Text label = new Text("ComboLabel :");
    label.setStyleName("combo-text-label");
    label.setTagName("span");
    hp.add(label);
    hp.add(comboWidget);
    
    .combo-text-label {
    font-family:tahoma,arial,helvetica,sans-serif;
    font-size:12px !important;
    font-size-adjust:none;
    font-style:normal;
    font-variant:normal;
    font-weight:normal;
    line-height:20px !important;
    padding: 2px;
    height: 100%
    }

    GXT Lockable Grid Columns

    Due to the lack of this feature, I’ve hacked a rough version of a grid with lockable columns. It’s a starting point – a layout container with the target grid passed in and it creates a left hand side grid that contains the locked columns. Future enhancements would be to do all this in a GridView sub class, eliminating the separate class.

    Updates here (V0.8).

    GXT Grids – Enable text selection

    In GXT the grids have text selection disabled by default (possibly for good reason). I haven’t found out any disadvantages to enabling text selection yet, so here is the code and go and copy and paste freely from grids to Excel…

    final Grid<Stock> grid = new Grid<Stock>(store, cm);
    
    grid.addListener(Events.Render, new Listener<BaseEvent>() {
        public void handleEvent(BaseEvent be)
        {
            grid.disableTextSelection(false);
        }
    });
    

    Update: I have seen some references to using:

    grid.removeStyleName("x-unselectable");
    

    Also in the newer versions of GXT I don’t think you need to add the listener any more (I haven’t confirmed this).