http://www.developer.com/

Back to article

Introducing a Lightweight UI Toolkit: Bringing Desktop Development into Java ME


July 17, 2008

Sun Microsystems announced LWUIT at the last JavaOne Conference. It is an advanced user interface library, a feature much desired by JavaME developers. With LWUIT [1], you can develop powerful interfaces avoiding lcdui Form's constrains and without reinventing the wheel. In this series of articles, you are going to develop a simple but complete application to show weather forecasts (reading a RSS from Yahoo! Weather [2]), showing different capabilities from this library. Although it is still too soon to consider it stable, the source code isn't published yet, and there aren't too many devices "officially" tested (although it is in fact very portable between devices), LWUIT is one of the most important innovations in the JavaME world.

First of all, I will suppose that you've had some experience with JavaME in the rest of these articles, and also a very little knowledge of Swing would be useful but it is not necessary. If you want a good introduction to JavaME, you have a series of articles [5], and to learn to develop JavaME applications, you can read this [7] great series of articles on developer.com.

What Is the Problem with JavaME?

This section is interesting only for programmers who never have developed a JavaME application, because every JavaME developer has encountered the same pitfalls when trying to make an appealing user interface. When Connected Limited Device Configuration was designed (the first JCP standards are from 2000), devices were really limited: a small number of colors, low resolutions, processing abilities. So, device limitations imposed the design and implementation of MIDP's lcdui package, which group all classes used for graphic user interfaces, in many ways:

  • No control over general appearance: A device's MIDP implementation has absolute control over it.
  • No Layouts, or speaking properly, only one: the vertical box layout.
  • No advanced custom Widgets: MIDP2.0 introduced CustomItem class, but it was so limited that majority of real developments preferred to use Canvas class directly.
  • No Animations
  • You have only Canvas (in full screen mode starting with MIDP 2.0) and your skills if you want advanced features: and this is not good if "creating a new GUI components library for JavaME" is not the objective of your project.

But, after many years, Sun surprised JavaME developers around the world, presenting at 2008 JavaOne an internal project: LWUIT. The aim of this project is to bring the Swing/AWT programming paradigm to JavaME, to avoid fragmentation and to provide advanced UI functionality.

Introducing the API

To solve some of the problems of lcdui, LWUIT adopts a model similar to AWT, which uses a Composite Pattern [8], adapting it to existing limitations in mobile phones. Everything is a Component, and a Container is a Component that can hold other Components. By using nested containers, you can create a complex user interface.

Figure 1: Simplified Component hierarchy

Another interesting feature introduced by LWUIT is that components own Style objects, where you can change font, color, padding, and margin (a box-model very similar to CSS), and transparency. It also allows you to create Themes, a Java properties file that defines Component styles in your application. By using themes and styles, that can be changed at runtime, it is very easy to change the complete appearance of your application.

As an user interface API, LWUIT abstracts only lcdui classes; you can't access Canvas (if you were thinking of doing it to combine a component UI and some low-level painted screens). It was created that way to avoid device implementation fragmentation and also to generalize the API to be usable in another environments (like CDC, available in some smart phones and PDA's).

I'm not going to start a exhaustive list of all Components (all of us are programmers and know what a javadoc is); I always think that an example of programming is better than thousands of lines of theory, so let me start with a simple application that uses LWUIT.

Introducing LWUIT: Weather Application

You are going to develop a very simple application that connects to Yahoo Weather Service [2], parses received RSS, and shows the weather forecast in a beautiful way. Along your way, you are going to start with a very poor (and boring) MIDlet and you will add additional features of LWUIT showing some of the most important capabilities of the library. In this article, you are going to work with only two screens: a first main menu with two buttons, and a result page for showing weather forecasts.

You have information about Yahoo's RSS weather on [3]. To parse that RSS, you will use KXML [6], the Swiss army knife for parsing XML on mobile phones thanks to its small size (10Kb) and memory footprint. At the end of the article, you can find a download link of a Netbeans project with all the source of this application; you will need Netbeans 6.1 with Mobility support installed.

At this moment, you can download only a binary version of LWUIT (you are going to use version 20080625) in [1]; the source code is supposed to be downloadable when version 1.0 is be released. This binary has a Sun License Agreement; thish allows you to use it on commercial products for free; the source code is licensed under the well-known by Java developers GPLv2 with the classpath exception.

Before starting, you will add the LWUIT library to Netbeans; that way, all mobile projects developed inside your IDE can use it. Go to Tools > Libraries, and add the LWUIT jar you downloaded from [1] on the Classpath tab. If you add javadoc in the corresponding tab, you will enjoy the integrated help of the Netbeans editor.



Click here for a larger image.

Figure 2: Libraries dialog showing Javadoc tab

Creating the Midlet

You have to create a new Mobility project (New Project > Mobility > MIDP Application); the only thing to take care of is to select MIDP-2.0 as a "Device Profile" in the "Default Platform Selection" display because you want to cover the majority of current phones. In the "Resources" node, select "Add Library" and select LWUIT from that dialog. At the end, you will have a LWUIT-capable mobile app.

You have all the code at the end of this article, packaged as a Netbeans mobility project. But let me start with a very simple approach to show you what the appearance of your LWUIT applications will be when you start them from scratch. As I said, LWUIT only covers lcdui classes, so your MIDlet will be a normal MIDlet, with some new additions to MIDP:

public void startApp() {
   ...
   // With LWUIT, you always have to do this
   Display.init(this);

   // Form is a display
   Form mainMenu = new Form("Yahoo Weather with LWUIT");
   // Like Desktop apps, it needs a Layout
   mainMenu.setLayout(new BorderLayout());

   // We need a Container to place buttons
   Container mainContainer =
      new Container(new BoxLayout(BoxLayout.Y_AXIS));

   // Some buttons that define the main menu
   getWeatherButton = new Button("Get Weather!");
   setPlaceButton   = new Button("Set Place");

   // As in Java SE, somebody has to listen and act.
   // It is declared as a private class.
   ButtonActionListener buttonListener =
      new ButtonActionListener();
   getWeatherButton.addActionListener(buttonListener);
   setPlaceButton.addActionListener(buttonListener);

   // Adding components to containers
   mainContainer.addComponent(getWeatherButton);
   mainContainer.addComponent(setPlaceButton);
   mainMenu.addComponent(BorderLayout.CENTER, mainContainer);

// Add soft buttons to the form
   mainMenu.addCommand(exitCommand);
   mainMenu.addCommand(aboutCommand);
   mainMenu.setCommandListener(this);
   // Finally, show it on screen
   mainMenu.show();

...

The first interesting thing is that you always have to pass a Midlet reference to the Display class, before showing any Form on the screen. Display is a very important class that controls the Event Dispatch Thread: a thread where all events (key pressed, key released, painting, and so forth) happens; this is very similar to the Swing EDT. I will speak more about EDT in the next article, when you focus on animations.

Don't confuse the LWUIT Form class with the lcdui one. Form is the top-level container of the UI and it also, as lcdui one, controls and shows one screen. But, it differs mainly from its grandfather in the fact that it can hold not only widgets but also containers, and that you only need to call its show() method to paint it onscreen.

Forms have three different areas on screen:

  • A title bar
  • A menu bar, where software buttons are laid
  • A content pane, where you are supposed to add components

As in Java SE, you have to specify how you want to place components inside your Container. You have five different Layouts:

  • BorderLayout: Similar to its desktop big brother, defines four areas where you can place components: NORTH, SOUTH, EAST, and WEST
  • BoxLayout: Your components will be placed horizontally or vertically
  • FlowLayout: Your components will be placed one after another in a row. If their width overflows the complete width of the screen, there will be multiple rows
  • GridLayout: Places components in a grid of cells
  • GroupLayout: This is the same as GroupLayout created for GUI Builders such as Matisse. You can use it, but I think that its importance is going to be greater on the future. Sun is giving some hints about their future plans with LWUIT: create a mobile GUI builder using these LWUIT components as a palette. So, stay tuned for future news.

As you can see, you can combine different containers with different layouts. The strength of using this approach based on layouts is that components will maintain relative position between them. So, your GUI will have a similar appearance without being overly affected by differences in the device's resolutions. If sometimes you have been obliged to draw your components directly on a Canvas, you may see Layouts as a step forward to minimize fragmentation in user interfaces.

To add real functionality to your buttons, I also defined an ActionListener. When the user presses a button, the actionPerformed method is called. In your case, it simply creates a connection to Yahoo! Weather, parses the RSS, and shows a screen with results.

As with every mobile application, I added two soft buttons to the screen: exit and about. The way to include those buttons is to create Commands and add them to a Form with the addCommand method.

The result of adding those buttons is shown in Figure 3.

Figure 3: First Lwuit Screen

I'm not going to explain extensively how the RSS is parsed because it is not related to the main topic, but I'll provide some comments to help you better understand the code. If you use KXML, getting a RSS feed is as simple as this:

parser = new KXmlParser();
HttpConnection conn = (HttpConnection) Connector.open(
"http://weather.yahooapis.com/forecastrss?p=SPXX0016&u=c");
InputStream rssStream = conn.openInputStream();
InputStreamReader isr = InputStreamReader(rssStream);
parser.setInput(isr);

At this point, I set the place for which you want to obtain a weather forecast hard-coded (it is Bilbao, in Spain, a city near where I live). If you want to set your city: location parameter of the URL (p) can be a U.S. Zip code or a location ID. To find your location ID, browse or search for your city from the Yahoo! Weather home page. The weather ID is in the URL for the forecast page for that city.

After parsing Yahoo's response, you will have a YahooWeather object populated with all the information you want to show. So, it's time to create a view.

Show the Results

The following code shows the main parts of the WeatherDisplay class.

form.setTitle(weatherRss.title);
form.setLayout(new BoxLayout(BoxLayout.Y_AXIS));

Container conditionContainer = new Container(new BorderLayout());
Label textCondition = new Label(weatherRss.actualCondition.text);
...
Container center = new Container(new BoxLayout(BoxLayout.Y_AXIS));
center.addComponent(humidity);
...
conditionContainer.addComponent(BorderLayout.NORTH, textCondition);
conditionContainer.addComponent(BorderLayout.WEST,  icon);
conditionContainer.addComponent(BorderLayout.EAST,  temp);
conditionContainer.addComponent(BorderLayout.CENTER, center);

Button link = new Button("Get_complete_forecast");
link.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent arg0) {
      try {
         weatherMid.platformRequest(weatherRss.link);
      } catch (ConnectionNotFoundException ex) {
         ex.printStackTrace();
      }
   }
});
form.addComponent(conditionContainer);
form.addComponent(link);

As I said earlier, you nested a BoxLayout Container inside the CENTER of a BorderLayout Container. That, in turn, is placed on a BoxLayout Form. Basically, this way, I know that the temperature is always going to be shown on right border, and that other weather parameters always are going to be shown on the center of the screen.

So, the final result is shown in Figure 4. In Figure 5, with a smaller resolution, a scroll appeared but the relative positioning of all elements is maintained.

Figure 4: Displaying poor results

Figure 5: Scroll appears in small screens

Boring? Yes! Use Styles and Resources

Okay, you have seen that with LWUIT you have more possibilities to design your screens than with the ancient lcdui package, but to be honest, at this point your app seems only a little better than old apps.

LWUIT adds a new concept to mobile UI components: a Style object associated with every element shown on the screen. You can modify color, font, margin and padding, background images, and even how the background is painted (using Painters, that you will see in the next article). The way to do it is to get the Style object associated to a component and change its properties, as shown in the next code sample (colors must be expressed in RGB notation):

Button link = new Button("Get complete forecast");
link.getStyle().setBgSelectionColor(0x000000);
link.getStyle().setBgColor(0xFFFFFF);
link.getStyle().setFgColor(0xFFAABB);

But, setting every component's appearance programmatically might be tedious and error-prone, so LWUIT offers an alternative way to declare styles, Themes: Java properties files that specify all style parameters of UI items. You have an example in the following listing.

fgSelectionColor= 0017ff
font= System{ FACE_SYSTEM ; STYLE_PLAIN; SIZE_SMALL }
Form.bgImage=myBackground
Form.font=Bitmap{Serif}
SoftButton.bgColor= ff
SoftButton.fgColor= ffffff

Resources

Other things that beautify any program are images, icons, and fonts. LWUIT has the ability to bundle all resources in a single file, thereby improving compression (separate files always take up more bytes than a bundle of them, one lesson that you learn developing mobile apps). To ease creation and maintenance of resource files, apart from some ant task definitions, LWUIT developers distribute a resource editor application in the LWUIT download (util folder). And, good news for developers, it also could be used to create themes using a graphic interface. You won't have to remember all the keys of a theme file.



Click here for a larger image.

Figure 6: Theme Editor of ResourceEditor

What I miss about these themes is a way to distinguish different classes of the same component. At this moment, if you specify a background color of buttons in a theme, the only way to have a button with a different appearance is by changing its Style programmatically. Components with Style changed programmatically don't obey rules defined with themes unless you call Style setXXX methods with a boolean parameter set to true.

Images

Images are one of the big headaches for JavaME developers: you need them, but they very much increase the size of your jar, and loading too many images into memory could exhaust your phone's capacity fast.



Click here for a larger image.

Figure 7: Image Panel on ResourceEditor

LWUIT introduces the indexed image concept: images that occupy less memory, composed by two arrays, an array of integers (image pixels), and an array of bytes (pixel colors). Following this definition, it is easy to suspect what their caveats are:

  • Your images can have 256 only colors.
  • They are slower to render than normal images because they require a lookup for every pixel.
  • You have to use a resource file to use them because there isn't any standard implemented on devices that allows this kind of images.

I'm not going to use them in this project, but they may be very useful in an application with intensive use of graphics; for example, for defining background images on buttons, although using tiled images is even cheaper in terms of memory usage.

Another noteworthy point about the Image class is the inclusion of scaling methods on it; its lcdui counterpart lack of them. Although you lose some resolution on scaled images, they alleviate the need of adding a new bigger (or smaller) version of the file on the jar.

Fonts

With LWUIT, you can substitute a phone's implemented fonts, that often look awful, with nice, antialiased fonts. You can select any font installed on your computer, and create an archive inside the resources file that packages it to use in any component. You also can define what is going to be used in the charset; and in your case, don't forget to add a º (degree symbol) to mark angles and temperatures.



Click here for a larger image.

Figure 8: Font maker

Loading a theme and resources

After defining your theme, adding your images, and setting your fonts, your app needs to load all this information. I put the resources file on the default package in the src directory, to be packed easily in the jar by Netbeans, but you can modify the proportioned ant script to satisfy your needs. To load your theme, you have to open your resource file, set your theme on UIManager (Singleton class that manages the look of the application), and at least, if you are using WTK as an emulator, refresh the theme on Display. I didn't find any reference in the LWUIT documentation but until I had refreshed my theme, my changes weren't shown. If you plan to change themes at runtime, you also have to refresh it. In the following three lines of code, the created theme is applied to the weather app:

res = Resources.open("/weather.res");
UIManager.getInstance().setThemeProps(res.getTheme
   (res.getThemeResourceNames()[0]));
...
//Without doing this, the theme is not shown
Display.getInstance().getCurrent().refreshTheme();

To load images from the resource file, you simply call the getImage method, and to change their size, call scaling methods, as shown here.

Label icon =
   new Label(resources.getImage(weatherRss.actualCondition.code +
             ".png").scaled(40, 40));
When you select your obfuscating level on project properties, don't set it very high or calls to Image.scaled() will fail, exiting your application. For example, I selected a level of 4.

In the WeatherDisplay class, I show a scaled image for the "actual condition," and I use the normal size image for "forecast." And here you have final result:

Figure 9: A more polished screen

Figure 10: Good read on small screens

Please, feel free to open weather.res file in your Resource Editor and play with different combinations of colors, fonts, and images. Maybe some of you wonder why I have included all the images inside the resource file instead of downloading them (the RSS feed has some image URLs). Basically, I did this for two reasons: to show you how to include images, and secondly, some mobile operators control how much bandwidth is used by customers, and I wanted to consume the minimum possible.

Conclusion

You have learned the basics of LWUIT: using containers and forms and placing components on them following a layout. You also started to empower your application with themes, fonts, and images. In the next article, I will show you some advanced concepts, such as Lists, dialogs, tabs, and animations.

Download the Code

You can download the code that accompanies this article here.

References

About the Author

Ibon Urrutia is a Spanish IT Engineer, with wide experience in JavaME applications targeted to be used in many devices. Nowadays, he is working for MDTEC http://www.mdtec.net, participating in a complete JavaME framework with advanced user interface functionalities, TagsMETM, http://www.tagsme.com. He also is member of Netbeans Dream Team, http://wiki.netbeans.org/NetBeansDreamTeam.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date