GWT Ext - How to set background color and an image icon in the same grid-cell

Problem #1:
I must set a background color and I must renderer an image icon in the same grid-cell. How can I set this for a grid-cell?


Solution #1:
You get the solution from this posting "how to set grid-cell background"  and update it like in  the following example:

String htmlAttr = "style='background-color:yellow; background-image: url(gray_gradient.gif);background-repeat: no-repeat;'";

cellMetadata.setHtmlAttribute(htmlAttr);



Problem #2:
The method described works, but the image is not centered. How can I do it?


Solution #2:
To center the background image of your grid cell you have to add to the "style" this new attribute:
background-position, like in the following example:

String htmlAttr = "style='background-color:yellow; background-image: url(gray_gradient.gif);background-repeat: no-repeat;background-position:50%;'";

cellMetadata.setHtmlAttribute(htmlAttr);


I'm glad I could help.



Cheers!

GXT - How to change the background color of a TextField

To change "programmatically"  the background color for a TextField control from GXT (Ext GWT) you can do it either by setting directly the "background-color" CSS attribute or by assigning a new CSS class.

We have used the "safe call" function safeFunctionCallOn, explained in a previous posting, to avoid pitfalls of rendered vs non-rendered control, which may have or not created the DOM element.

Here's the static helper functions  to do this:

 /* Sets a style attribute for the  text-field control */
public static void setTextFieldAttr(final Field<?> textField, final String cssAttrNm, final String attrVal) {
safeFunctionCallOn(textField, new Function() {
@Override
public void execute() {
textField.el().firstChild().setStyleAttribute(cssAttrNm, attrVal);
}
});
}


 /* Assigns a new CSS style class to the field control  */
public static void setTextFieldStyle(final Field<?> textField, final String cssStyleNm) {
safeFunctionCallOn(textField, new Function() {
@Override
public void execute() {
textField.el().firstChild().setStyleName(cssStyleNm);
}
});
}

And with this we can set by program any appearance of the text-field or other fields (combos, passwords, numbers), like in the following examples:

   TextField textField = ...
   setTextFieldAttr(textField, "font-size", "11px");
   setTextFieldAttr(textField, "background-color", "#e6e6e6");

   setTextFieldStyle(textField, "gwt-x-small-red"); // where gwt-x-small-red is defined in .CSS file 
   

Cheers!

GWT - Configure DevMode "port" and "codeServerPort" options

All options for the DevMode are listed below, and the most used, even if you don't know it, are "port" and "codeServerPort". These are used all the time to launch the application in dev-mode, using the well-know URL:

h t t p : / / localhost : 8888 / MyModule.html ? gwt.codesvr = localhost : 9997

- where "port = 8888" and "codeServerPort = 9997".

The command  line for starting the development mode for Google Web Toolkit 2.0.2, which Eclipse plugin hides from us, is presented here:

DevMode [-noserver] [-port port-number "auto"] [-whitelist whitelist-string] [-blacklist blacklist-string] [-logdir directory] [-logLevel level] [-gen dir] [-bindAddress host-name-or-address] [-codeServerPort port-number "auto"] [-server servletContainerLauncher[:args]] [-startupUrl url] [-war dir] [-extra dir] [-workDir dir] module[s]

where:
  • -port                       Specifies the TCP port for the embedded web server (defaults to 8888)
  • -codeServerPort    Specifies the TCP port for the code server (defaults to 9997)
  • -noserver               Prevents the embedded web server from running  
  • -whitelist                Allows the user to browse URLs that match the specified regexes (comma or space separated)
  • -blacklist               Prevents the user browsing URLs that match the specified regexes (comma or space separated) 
  • -logdir                    Logs to a file in the given directory, as well as graphically
  • -logLevel               The level of logging detail: ERROR, WARN, INFO, TRACE, DEBUG, SPAM, or ALL 
  • -gen                        Debugging: causes normally-transient generated types to be saved in the specified directory
  • -bindAddress         Specifies the bind address for the code server and web server (defaults to 127.0.0.1)
  • -server                   Specify a different embedded web server to run (must implement ServletContainerLauncher)
  • -startupUrl             Automatically launches the specified URL 
  • -war                        The directory into which deployable output files will be written (defaults to 'war'
  • -extra                     The directory into which extra files, not intended for deployment, will be written
  • -workDir                The compiler's working directory for internal use (must be writeable; defaults to a system temp dir) 
  • module[s]               Specifies the name(s) of the module(s) to host.
If you use Eclipse, like most of us, then to change the default settings of the GWT ports (port & server port) you have to set your launching command like in the below image, where I set as exemple the GWT port = 8877 and the dev-mode plugin port codeServerPort = 9977; so in this case the launching URL will be:

h t t p : / / localhost : 8877 / MyModule.html ? gwt.codesvr = localhost : 9977


So, this is the list of GWT Dev-Mode command line parameters. Have fun !

Cheers!

GWT - How to implement the GXT's DelayedTask in pure GWT ?

In the GXT framework there is a class called DelayedTask, which is a Timer that is cancelled if a new request is made. So, when we need such thing? Usually when we have multiple identical actions that are ocurring repetately (i.e. mouse event, or layout requests when modify content of the panels), and we'd like to ignore all calls except the last one.

To get the same functionality in pure GWT, which obviously will work well using different widget frameworks (GWT-Ext, pure GWT, GXT or SmartGWT), is presented in the class LastCallBurstEventsMgr, available for download HERE.

The class LastCallBurstEventsMgr takes care of the burst of the same event, by skipping the first ones and executing only the last one.
 
An example of a call for this class is presented below:

scrollPanel_.addScrollListener(new ScrollListener() {

    public void onScroll(final Widget widget, final int scrollLeft, final int scrollTop) {

        LastCallBurstEventsMgr.addEvent(
            new BurstEvent("scroll-me-baby-one-more-time",
                           new Function() {
                               public void execute() {
                                    System.out.println(" scrollLeft = " + scrollLeft + " scrollTop = " + scrollTop + " widget = " + widget.getClass());
                               }
                           },
                           200)
        );
    }
});

which means for each event with the same unique name 'scroll-me-baby-one-more-time' the manager will defer the execution if in the last 200 msec (like in the above exemple) another event has arrived, otherwise it launches the "Function" callback. So, in case of only one single event this code adds a latency of 200msec, which depends of your application if it acceptable of not.

Cheers!

Java Swing - Automatically resize the JTable columns based on its values

I know that this problem I solved using before GWT-Ext, and now the time has come to make public the source code, which performs exactly the same thing 'auto-resize of the column based on the length of values from within the cells', but using Java Swing.

Below, there are defined 2 static functions that will do the trick (first one is public and call-able ddirectly in your code; the second one is a helper for the first one).

/**
 * Sets the table column width (column width = lenOfChars * 8)
 */
public static void resizeTable(JTable table, boolean... onlyIfBigger) {
    if (table != null) {
        boolean resized = false;
        int resizeMode = table.getAutoResizeMode();
        table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
       
        int tw = 0;
        int size = table.getColumnCount();
        for (int col = 0; col < size; col++) {
             String longerValue = "";
             int longerRow = 0;
             for (int row = table.getRowCount(); --row >= 0;) {
                 Object value = table.getValueAt(row, col);
                 String val = (value == null ? "" : "" + value);
                 if (val != null && val.length() > longerValue.length()) {
                      longerValue = val;
                      longerRow = row;
                 }
            }
            tw += setTableColumnWidth(table, tw, longerRow, col, onlyIfBigger);
            if (tw != 0) {
                resized = true;
            }
       }

       if (!resized) {
           table.setAutoResizeMode(resizeMode);
       }

       int prefWidth = 0;
       TableColumnModel tcm = table.getColumnModel();

       for (int i = 0; i < tcm.getColumnCount(); i++) {
           TableColumn tc = tcm.getColumn(i);
            prefWidth += tc.getPreferredWidth();
       }

        int prefHeigh = table.getModel().getRowCount() * table.getRowHeight();
        table.setPreferredScrollableViewportSize(new Dimension(prefWidth, prefHeigh));
   }
}


/** Sets the table column width (column width = lenOfChars * 8) */
private static int setTableColumnWidth (JTable table, int currWidth, int longerRow, int column,
                                                            boolean... onlyIfBigger) {
    if (table != null) {
        TableColumnModel cm = table.getColumnModel();
        TableColumn colVal = cm.getColumn(column);

         if (table.getRowCount() == 0) {
             return 0;
         }
         boolean last_column = false;
         if (cm.getColumnCount() - 1 == column) {
             last_column = true;
         }

        Object value = table.getValueAt(longerRow, column);
        TableCellRenderer tcr = table.getCellRenderer(longerRow, column);
        Component c = tcr.getTableCellRendererComponent(table, value, false, false, longerRow, column);
        if (c instanceof JLabel) {
            value = ((JLabel) c).getText();
        }

        String longerValueStr = (value == null ? "" : "" + value);
        FontMetrics fm = table.getFontMetrics(c.getFont());
         int width1 = c.getPreferredSize().width + 6;
         int width2 = fm.stringWidth(longerValueStr) + 12;
         int width3 = 0;

         String header = (String) colVal.getHeaderValue();
         try {
             tcr = colVal.getHeaderRenderer();
             Component hc = tcr.getTableCellRendererComponent(table, header, true, true, 0, column);
             if (hc instanceof JButton) {
                 JButton bb = new JButton(header);
                 width3 = bb.getPreferredSize().width + 16;
            } else {
                 width3 = hc.getPreferredSize().width;
             }
         } catch (Exception e) {
             width3 = fm.stringWidth(header == null ? "" : header);
         }

         int width = Math.max(Math.max(width1, width2), width3);
         int oldLen = colVal.getPreferredWidth();
         int w = oldLen;


         if (onlyIfBigger.length > 0 && onlyIfBigger[0]) {
             if (width > oldLen) {
                  w = width;
             }
        } else {
             if (width != oldLen) {
                  w = width;
             }
         }


         if (last_column) {
               int orig_tw = table.getPreferredScrollableViewportSize().width;
               if (orig_tw - currWidth > w) {
                    w = orig_tw - currWidth;
              }
         }

         colVal.setPreferredWidth(w);
         return w;
    }
    return 0;
}

I hope it helped, even if the Swing development is on a descendant trend ... there are still some developers left out there.

Cheers!

Mobile - Service API changes starting with Android 2.0

Android 2.0 introduced a number of changes and improvements in this area for both developers and users.

The three main changes to be aware of are:
  • Service.setForeground() is now deprecated and in 2.0 does nothing.
  • There were many edge cases in the service lifecycle that made it very easy to accidentally leave a service running; new APIs in 2.0 make this much easier to deal with.
  • Android 2.0 also introduces a new UI for end users to monitor and manage the running services on their device.
Background on services

Before going into the details of 2.0, it may be useful to go over a quick summary of services. The Service API in Android is one of the key mechanisms for applications to do work in the background. Due to the way Android is designed, once an application is no longer visible to the user it is generally considered expendable and a candidate to be killed by the system if it ever needs memory elsewhere. The main way applications get around this is by starting a Service component, which explicitly tells the system that they are doing some valuable work and would prefer that the system not kill their process if it doesn't truly need to.

This is a very powerful facility but along with that power comes some responsibility: an actively running service is taking resources away from other things that can run (including inactive processes in the background that don't need to be initialized the next time the user visits them). It is thus important that developers take care when designing their services that they only run when truly needed and avoid any bugs where they may accidentally leave the service running for long durations.

Redesigning Service.setForeground()

During the final stabilization period of Android 1.6 we started to see more issues due to an increasing number of applications using the Service.setForeground() API when they shouldn't be. This is an API that we haven't advertised much because it should not be used by most applications and can be very hard on the system: it asks that the service's process be treated as in the foreground, essentially making it unkillable and thus more difficult for the system to recover from low memory situations.

Service lifecycle changes

Another situation we were increasingly seeing in 1.6 was that, even ignoring the services that inappropriately make themselves foreground, we had a growing number of devices with a large number of services running in the background all fighting each other over the available memory.

Part of this problem is services that are running more than they should or there simply being too much stuff trying to be done on the device. However, we also found many issues in the interaction between services and the platform that made it easy for an application to leave a service running even when it is trying to do the right thing. Consider this typical scenario:
  1. An application calls startService().
  2. That service gets onCreate(), onStart(), and then spawns a background thread to do some work.
  3. The system is tight on memory, so has to kill the currently running service.
  4. Later when memory is free, the service is restarted, and gets onCreate() called but not onStart() because there has not been another call to startService() with a new Intent command to send it.
Now the service will sit there created, not realizing it used to be doing some work, and so not knowing it should stop itself at some point.

New "running services" user interface
Our final issue to address is the case where there are simply too many service running in the amount of memory available on a device. This may be due to bugs or design flaws in installed applications, or the user simply trying to do too much. Historically users have had no visibility into what is going on at this level in the system, but it has become important to expose this, at least for lower-end devices, as the use of services has had an increasing impact on the user experience.
To help address this, Android 2.0 introduces a new "Running Services" activity available from the Application system settings.


READ MORE >>>

Cheers!

GWT - Date and Timestamp RPC serialization problem

Problem:

We have the client and servers in different time zones  (i.e server is in GMT and client is running in PST time zone), and we have to serialize through RPC a Date (Timestamp) object -- the Date_Serializer class does timezone conversion for Date/Time and Timestamp using long value of miliseconds, which means that the server is converting the Date  --> long using the function date.getTime(), send the long through RPC, and the client is converting the long --> Date, using the constructor Date(long), which will use the client time-zone. All is fine, that means the long value means the universal time since January 01, 1970 ... which is the same in all the time-zones, but when converted to a time-zone or another, we get different representation of that date.

Question: But, what if we want to send a Date like a constant (i.e. 2010-01-23 11:25:00) from server and to get on the client exactly the same value (i.e. 2010-01-23 11:25:00) ?

I saw lots of answers/solutions related with this issue, same of them recommended to replace the GWT serialization class for Date (com.google.gwt.user.client.rpc.core.java.util.Date_CustomFieldSerializer), which sends instead of one long value, 6 integer values (year, month, day, hour, minute and seconds) thru RPC.

Solution:

The simplest solution is to change your RPC function return parameter "Date" with something else, which isn't sensible to the time zone. So, you have to define your one "transporter" object to send the date as you want. Here is an example code:

/* define the class to extend IsSerializable marker interface */
public class MyGwtSafeDate implements IsSerializable {
    public int year, month, day;
    public int hour, minute, second;

    /* need this one for serialization constraint */
    public MyGwtSafeDate () {
    }

    /* add here the accessors and modifiers -- setters and getters */
}

and  after that change the function from your RPC service interface definition  to use the MyGwtSafeDate instead of Date.

/* this will be in your RPC service interface, Async and implemenation */
public MyGwtSafeDate getEnrollingDate (int customerId);

Having this simple change you will not have time-zone conversion problems for the Date, and you can process it on client as you want/need.

Cheers!

PS1: some problems may appear if you want to convert that MyGwtSafeDate object to Date, back and forth, on the client side, especialy for the US/Eastern time zone. It seems that there is a bug in the building the Date from the individual values like year, month, day, hour, minute and second ... but I didn't catch it yet :-(

PS2: I got the solution for PS1) and this is so simple, use constructor Date(year, month, day, hour, minute, second) instead of Date(long) and then setting individually these values (setYear, setMonths etc).

PS3: So, if you still have to compute on the client side some temporal difference, like startDate - 1hour, you have to do it like this:
- always keep your dates in another structure, i.e. MyGwtSafeDate. 
- convert MyGwtSafeDate to Date using Date (year, month, day, hour, min, sec) constructor.
- perform the difference throu "newLong = Date.getTime() - delta"
- convert the newLong throu Date (long)
- get the individual values from the Date to your MyGwtSafeDate object.

Enjoy it!

GXT - ImageBundle support


ImageBundle support has been an often requested feature. With M3, we have added ImageBundle support. Icons can be specified in three different methods:
  • AbstractImagePrototype (typically from an ImageBundle)
  • CSS style name (existing method)
  • Image path (String)
All components that support icons now implement the new IconSupport interface:
/**
 * Interface for objects that support icons.
 */
public interface IconSupport {
  /**
   * Returns the icon.
   * 
   * @return the icon
   */
  public AbstractImagePrototype getIcon();
 
  /**
   * Sets the icon.
   * 
   * @param icon the icon
   */
  public void setIcon(AbstractImagePrototype icon);
 
  /**
   * Sets the icon style.
   * 
   * @param icon a CSS style name
   */
  public void setIconStyle(String icon);
}
In addition, there is a helper class, IconHelper, that can be used to create image prototypes from CSS style names, and image paths. Here is an example setting an icon 3 different ways:
// from bundle
    item.setIcon(GXT.IMAGES.editor_bold());
    // CSS style name
    item.setIconStyle("my-icon");
    // image path
    item.setIcon(IconHelper.createPath("/my/url/foo.gif"));
When using ImageBundles, you create classes that extends ImageBundle. Here is a partial look of the new XImages class, which is the ImageBundle GXT uses for all it’s icons:
public interface XImages extends ImageBundle {
  @Resource("hmenu-asc.gif")
  AbstractImagePrototype grid_sortAsc();
 
  @Resource("hmenu-desc.gif")
  AbstractImagePrototype grid_sortDesc();
  ....
}
One immediate benefit we have noticed, is that the icons display immediately when first displayed in the application, rather than incrementally as a page loads. This happens since all the images are combined into one on the server at compile time, and therfore, 1 http request.

Cheers!

Question: I'm very curious how SmartGWT is managing this issue ? Thanks.


GXT, GWT Ext - Safe call of the "after render" kind of functions

Problem:

How many times did you have problems with calling a widget function (after-rendering), which is working only after the widget was rendered?

Solution:

The main idea is to delay the execution of the function after the widget was rendered. How we can do this? Very simple, just adding a handler function on render event. Here's presented the solution source code for the best 3 libraries:
  • using GXT framework
public interface Function {
    public void execute ();
}

/**
* Safe function call on a component, which was rendered or not.
*
* @param c Component object that must be not null.
* @param f Function object with the function that must be called.
*/
public static void safeFunctionCallOn(final Component c, final Function f) {
    c.enableEvents(true);
    if (c.isRendered()) {
        f.execute();
    } else {
        final Listener lsnr = new Listener() {
            @Override
            public void handleEvent(final ComponentEvent be) {
                f.execute();
            }
        };
        c.addListener(Events.Render, lsnr);
    }
}

  • using GWT-Ext framework
For this library we don't have to define the "Function" interface, like in the above code, because it's alredy defined in the GWT-Ext jar:

/**
* Safe function call on a component, which was rendered or not.
*
* @param c Component object that must be not null.
* @param f Function object with the function that must be called.
*/
public static void safeFunctionCallOn(final Component c, final Function f) {
    if (c.isRendered()) {
         f.execute();
    } else {
        c.addListener("render", f);
    }
}

  • using SmartGWT framework:
Also, for this library we don't need to define the interface "Function", because it already exists in the SmartGWT jar.

/**
* Safe function call on a canvas, which was rendered or not.
*
* @param c Canvas object that must be not null.
*
* @param f Function object with the function that must be called.
*/
public static void safeFunctionCallOn(final Canvas c, final Function f) {
    if (c.isDrawn()) {
        f.execute();
    } else {
        c.doOnRender(f);
    }
}

Note: the static function "safeFunctionCallOn" is safe to be called for either non-rendered or rendered widget, because its execution will always be deferred after the widget was rendered !

The call of this function is very simple, like here:

final Component panel = ...
safeFunctionCallOn (panel, new Function() {
    @Override
    public void execute() {
         /* after-rendering function */
         panel.setSomethingFunction (); 
    }
});

There is the other type of functions (before-rendering), which must be called before the widget was rendered. You'll have an error at runtime if you call the function after the widget was rendered. So, for solving this, you have to move the call of the function before the widget was added to a container.

Cheers!

Microsoft Office 2010 Beta - first glance

Hoourey !!! the Office 2010 Beta is available for download ... that's very nice. I followed the link and after login, got the green "Download" button. Nothing new so far, and as the "blue highlighted" text says "product is delivered by Click-and-Run, a streaming technology" -- kind of cloud-computing from Microsoft !?!

The "downloaded" file was an .exe with a funny name -- X16-19318_FBCYG-7YP8K-CFH3W-B6G4H-96X7W.exe --  (do not change it, the recommendation yells) and just 2MB size... 2MB indeed.

Double-click on it, and the "installation" starts, and after few moments the "PowetPoint" application starts with, obviously, the presentation of the new Office. So, "only 1 minute to install, start and run ?" I asked myself ... it should be a catch somewhere. And, indead, the PowerPoint starts, but perhaps, it just draws a screen an after that it starts downloading some "components", according with the indicator from the toolbar:

And wait, and wait ... type some keys ... and after a while the characters appear on the screen, and then it's stuck again, and again...

So, it's quick to see something, but it quite hard to use it, when it forces you to take breaks almost at every 10 seconds. Come on, I understand that you download live the DLLs, but after first time you have to cache it on my computer, not to download over and over again.

I just stopped the Office, and restart again, and the downloading crap starts ... so it's cool that you saved me time with the installation, but when you try to use it actually, you have to take "download break" too often.

>>> So, Microsoft needs to do smart improvements in caching and managing the internal components on local machine. <<<

There are good things too, all compoents have the same kind of user interface (UI), with , now clasic already, ribbon toolbar, which is trying to clean up (show the most used actions and tools) the very rich set of features.

There is a new "File" menu, which seems embedded (options are listed in the left side to be selected, and an editor panel for each one is available in the  right side), except the options "Options", which doesn't respect the UI pattern, to be consistent like the others, and pops-up a dialog on top of the main window, as you can see in the following images:



>>So, another need of improvement is: please, be consistent in UI, and open the Options dialog in the same kind of flat "editor panel" instead of heavy and ugly dialog <<<

A nice feature is the borrowed from Vista "screen clipping" that is available with OneNote, and easy to access through "Windows Key + S", very simple, and used a lot for the above images.

Another ugly point, if you use the Outlook with a "hotmail" account, it requires the "mail live plugin", which isn't downloaded automatically like the other hidden components, but it's done in the old way with a popup download dialog. So, the main issue here is: CONSISTENCY !

>>>So, if you decided to download automatically required components, do it the same for the mail-live plugin too <<<

I'm pretty sure that there are more stuff to discover and talk about, but it's "'night 'night" time, so I have to stop.

READ MORE >>>

Cheers!

Java - Debugging and testing Swing code

This is taken from "IBM DeveloperWorks"

When you need to use or maintain other Java™ developers' code, debugging and testing can help you understand how it works. In the case of visual code though, these powerful practices are more difficult unless you have the appropriate tools. The two open source tools that this article introduces — Swing Explorer and FEST-Swing — can make debugging and testing of Swing UIs simple and reliable.

Swing is one of the more powerful GUI toolkits available; it's extensible, configurable, and cross-platform. But Swing's flexibility is both its major strength and a great weakness. With Swing, you can construct the same UI in many different ways. For example, you can use insets, empty borders, or fillers to put space between GUI components. Given Swing's extensive stock of options, understanding an existing GUI can be as daunting a task as writing a new one, and mapping its visual appearance to the underlying code is far from trivial. (Try visualizing a GUI while reading a few lines of code that uses GridBagLayout.)

Whether you're maintaining Swing GUIs you didn't write or integrating third-party GUI components into your applications, a sensible approach to understand the code is to write tests. You explore the internals of the unknown code while writing the tests. As a valuable side effect, you end up with a test suite that can help prevent the introduction of regressions when you maintain the code. In the case of third-party GUI components, the test suite helps you find out if new a version of the library has introduced any behavioral changes.

 A good start is to write functional tests to understand how the GUI behaves in response to user input. Writing tests for GUIs is more complex than writing tests for non-visual code, because:
  • Ideally, tests must be automated, but GUIs are designed for humans — not computer programs — to use.
  • Conventional unit testing, involving tests of isolated classes, is unsuitable for GUI components. In GUI terms, a "unit" involves cooperation of more than one GUI component, which can itself consist of more than one class. 
  • GUIs respond to user-generated events. To test GUIs, you need a way to simulate user input, wait until the generated events have been broadcast to all listeners, and then check the result as the GUI would appear to the user. Writing code that simulates user interaction with GUIs can be tedious and error-prone. 
  • Changes in the GUI's layout should not affect robust functional tests.
An additional issue is that you must already know the structure and behavior of the GUI you want to test, otherwise you don't know which components the automated test should use and what needs to be verified. In general, to write a GUI test you must know:
  • The components that are present in the GUI to test
  • How you can uniquely identify such components in your tests
  • The expected state (or properties) of the components in a particular use case
You might be able to figure out a GUI's structure by using a visual design tool (such as NetBeans Matisse). But this type of tool shows only a GUI's design-time information, which can be different from what you see at run time. For example, some components may be made visible or invisible in response to user input.

Traditional debuggers cannot help you learn the state of a GUI while it's executing a particular use case. When the debugger stops at a breakpoint placed in Swing code, GUI painting is interrupted resulting in GUI that looks like a blank square. Ideally, you want to see how the GUI behaves while you step through it with a debugger.

Fortunately, two open source tools — Swing Explorer and FEST-Swing — can help you get up to speed quickly when you need to understand existing Swing code. This article introduces you to these tools, showing you how to use them in combination to inspect an application's GUI structure, test its functionality, and identify potential problems.
 
READ MORE >>>
 
Cheers!

GXT 2.1 - How to disable the default behaviour for HOME and END keys in the TabPanel ?

Problem:

I have a TabPanel with few tabs, and one of them has a "properties" editor. Some properties are edited using a TextField cotrol, and when I want to go to the beginning or end of the field I press, naturally, the keys HOME or END, and then the TabPanel container changes the selected tab to first one or last one... so I lose my focus on field editing ... very very ugly  indeed ! Workaround is "don't use HOME and END keys", but I can't help it -- I press them all the time :)

Is there a solution for this problem?

The answer for this question is very simple, YES, like the solution itself.

Solution:

We have to override the "pressed key handler" (good thing that it's protected, and not private), which is providing this ugly behavior, like in this sample code:

public class MyTabPanel extends TabPanel {
    /**
     * Override this function to get rid of the HOME, END keys problem.
     */
    @Override
    protected void onKeyPress (ComponentEvent ce) {
         /* do nothing */
    }
}

and then use the MyTabPanel instead of the default one. I know, this is an ugly simple solution, but efficient!

Cheers!