Skip Headers
Lightweight UI Toolkit Developer's Guide
Release 1.5
E23376-03
  Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

2 Using Lightweight UI Toolkit Widgets

This chapter introduces the LWUIT widgets and provides sample code for several components.

Component

A Component is an object having a graphical representation that can be displayed on the screen and can interact with the user. The buttons, check boxes, and radio buttons in a typical graphical UI are all examples of a component. Component is the base class. All the widgets in the Lightweight UI Toolkit library use the composite pattern in a manner similar to the AWT Container and Component relationship.

Container

A Container is a composite pattern with a Component object. It enables nesting and arranging multiple components using a pluggable layout manager architecture. Containers can be nested one within the other to form elaborate UIs. Components added to a container are tracked in a list. The order of the list defines the components' front-to-back stacking order within the container. If you do not specify an index when you add a component to a container, it is added to the end of the list (and hence to the bottom of the stacking order).

Form

Form is a top-level component that serves as the root for the UI library. This Container handles the title and menus and allows content to be placed between them. By default the form's central content (the content pane) is scrollable. Form contains Title bar, MenuBar and a ContentPane. Invocations of Form's addComponent method are delegated to the content pane's addComponent. The same applies to most composite related methods (e.g. setLayout, getComponent and so forth).

The following code demonstrates creation and setup of a form.

Example 2-1 Form Setup and Creation;

// 1. Create a Form
Form mainForm = new Form("Form Title");
// 2. Set LayoutManager
mainForm.setLayout(new BorderLayout());
// 3. Add a Label to the center of Form content pane
mainForm.addComponent(BorderLayout.CENTER, new Label(“Hello World”));
// 4. Set Transitions animation of Fade
mainForm.setTransitionOutAnimator(CommonTransitions.createFade(400));
// 5. Add Command key
mainForm.addCommand(new Command("Run", 2));
// 6. Show it
mainForm.show();

The following notes correspond to the comments in Example 2-1.

  1. The first line of code creates a form using a constructor that lets you set the form title. The other frequently used form constructor is the no-argument constructor.

  2. Next the code specifies the layout manager of the form. Layout managers are discussed later in this guide.

  3. The next bit of code adds a label to the form content pane. Adding components to a Form (which is a Container) is done with addComponent(Component cmp) or addComponent(Object constraints, Component cmp), where constraints are the locations in the layout manager, BorderLayout.

  4. A Transition is the movement effect action that occurs when switching between forms. See the Transitions and Animation chapter.

  5. Form has menus to emulate the device soft keys, for example. To set such a menu bar item, command, use the addCommand(Command cmd) method. The Commands are placed in the order they are added. If the Form has one Command it is placed on the right. If the Form has two Commands the first one added is placed on the left and the second one is placed on the right. If the Form has more than two Commands the first one stays on the left and a Menu is added with all the remaining Commands.

  6. The show method displays the current form on the screen.

Create and Set Up a Form Label

The Label widget can display a single line of text and/or an image and align them using multiple options. If you need to create a component that displays a string, an image, or both, you should use or extend Label. If the component is interactive and has a specific state, a Button is the most suitable widget (instead of a label).

To create a Label, use one of the following calls:

Label textLabel = new Label("I am a Label"); // for a text label

Create an image for an icon label:

Image icon = Image.createImage("/images/duke.png");
Label imageLabel = new Label(icon); 

Labels can be aligned to one of the following directions: CENTER, LEFT, RIGHT. LEFT is the default. In addition the text can be aligned relative to the image position. Valid values are TOP, BOTTOM, LEFT, RIGHT, where the default is RIGHT. To update the text position use:

setTextPosition(int alignment);

Figure 2-2 displays three types of labels with text to icon alignment position of RIGHT. The container is divided into three rows, and the label in each row is as wide as possible. Figure 2-3 shows relative alignment, with the label below the icon.

Figure 2-2 Label With Text, Label With Icon, and Label with Text and Icon

Description of Figure 2-2 follows
Description of "Figure 2-2 Label With Text, Label With Icon, and Label with Text and Icon"

Figure 2-3 Text to Icon Alignment Position of BOTTOM

Description of Figure 2-3 follows
Description of "Figure 2-3 Text to Icon Alignment Position of BOTTOM"

Button

The Button component enables the GUI developer to receive action events when the user focuses on the component and clicks. In some devices a button might be more practical and usable than a command option. Button is the base class for several UI widgets that accept click actions. It has three states: rollover, pressed, and the default state. It can also have ActionListeners that react when the Button is clicked.

To get the user clicking event, you must implement an ActionListener, which is notified each time the user clicks the button. The following code snippet creates an action listener and changes the text on the button, every time the user clicks it.

final Button button  = new Button("Old Text");
button.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent evt) {
         button.setText("New Text");
      }
   });

Button extends Label, so you can create three type of buttons: text only, image only or image and text button.

Figure 2-4 Button With Text, Button With Icon, and Button With Text and Icon

Description of Figure 2-4 follows
Description of "Figure 2-4 Button With Text, Button With Icon, and Button With Text and Icon"

RadioButton

RadioButton is a Button that maintains a selection state exclusively within a specific ButtonGroup. Because RadioButton inherits from Button, radio buttons have all the usual button characteristics, as discussed in Button. For example, you can specify the image displayed in a radio button. Each time the user clicks a radio button (even if it was already selected), the button fires an action event, just as in Button.

To create a RadioButton use:

RadioButton radioButton = new RadioButton(“Radio Button”);

Figure 2-5 shows the RadioButton this code produces.

Figure 2-5 Sample Radio Button

Description of Figure 2-5 follows
Description of "Figure 2-5 Sample Radio Button"

ButtonGroup

The ButtonGroup component manages the selected and unselected states for a set of RadioButtons. For the group, the ButtonGroup instance guarantees that only one button can be selected at a time.

Initially, all RadioButtons in a ButtonGroup are unselected. Each ButtonGroup maintains the selected index, and can get a specific RadioButton by calling getRadioButton(int index).

The following code snippet creates a button group made of two RadioButtons.

Label radioButtonsLabel = new Label("RadioButton:");
....
RadioButton rb1 = new RadioButton("First RadioButton in Group 1");
RadioButton rb2 = new RadioButton("Second RadioButton in Group 1");
 
   ButtonGroup group1 = new ButtonGroup();
   group1.add(rb1);
   group1.add(rb2);
 
exampleContainer.addComponent(radioButtonsLabel);
exampleContainer.addComponent(rb1);
exampleContainer.addComponent(rb2);

The code snippet result is shown in Figure 2-6.

Figure 2-6 RadioButton Group

Description of Figure 2-6 follows
Description of "Figure 2-6 RadioButton Group"

CheckBox

Check boxes are similar to RadioButtons but their selection model is different, because they can flip the selection state between selected and unselected modes. A group of radio buttons, on the other hand, can have only one button selected. Because CheckBox inherits from Button, check boxes have all the usual button characteristics, as discussed in Button. For example, you can specify the image displayed in a check box. Each time the user select a check box (even if it was already selected), it fires an action event, just as in Button.

To create a CheckBox use:

final CheckBox checkBox = new CheckBox(“Check Box”);

This code produces the CheckBox shown in Figure 2-7.

To catch select and unselect events you can try this:

checkBox.addActionListener(new ActionListener() {
   public void actionPerformed(ActionEvent evt) {
      if(checkBox.isSelected()) {
         System.out.println("CheckBox got selected");
      } else {
         System.out.println("CheckBox got unselected");
      }
   }
});

Figure 2-7 CheckBox Sample

Description of Figure 2-7 follows
Description of "Figure 2-7 CheckBox Sample"

ComboBox

A combo box is a list that allows only one selection at a time. When a user clicks the combo box button, a drop-down list of elements allows the user to select a single element. The combo box is driven by the list model and allows all the renderer features of the List as well.

Other components that can display one-of-many choices are groups of radio buttons, check boxes, buttons, and lists. Groups of radio buttons are generally the easiest for users to understand, but combo boxes can be more appropriate when space is limited or more than a few choices are available. Lists are not always attractive, but they are more appropriate than combo boxes when the number of items is large (say, over five).

The following code creates a combo box (a list model that is built from check boxes) and sets it up:

String[] content = { "Red", "Blue", "Green", "Yellow" };
 
// 1. Creating the combo box
ComboBox comboBox = new ComboBox(content);
 
// 2. Setting a checkBox renderer
comboBox.setListCellRenderer(new checkBoxRenderer());
 
// 3. Adding a action listener to catch user clicking
//    to open the ComboBox
 
comboBox.addActionListener(myActionListener......);

The following notes correspond to the comments in the code above.

  1. This combo box code contains an array of strings, but you could just as easily use labels instead.

  2. To put anything else into a combo box or to customize how the items in a combo box look, you need to write a custom renderer.

  3. The next line of code (which calls setListCellRender) registers an action listener on the combo box.

The following is a sample of renderer code:

/**
 * Demonstrates implementation of a renderer derived from a CheckBox 
 */
private static class checkBoxRenderer extends CheckBox implements ListCellRenderer {
 
      /** Creates a new instance of checkBoxRenderer */
      public checkBoxRenderer() {
         super("");
      }
 
      // Setting the current check box text and status
      public Component getListCellRendererComponent(List list,
                      Object value, int index, boolean isSelected) {
         setText("" + value);
         if (isSelected) {
            setFocus(true);
            setSelected(true);
         } else {
            setFocus(false);
            setSelected(false);
         }
         return this;
      }
 
      // Returning the list focus component 
      public Component getListFocusComponent(List list) {
            setText("");
            setFocus(true);
            setSelected(true);
            return this;
      }
   }

The sample code produces the combo box in Figure 2-8.

Tabs

Tabs are containers that let the user switch between a group of components that all share the same space by focusing on a tab with a title, an icon, or both. The user chooses which component to view by selecting the tab corresponding to the desired component.

To create a tab pane, instantiate Tabs, create the components you wish it to display, and then add the components to the tabbed pane using the addTab or insertTab methods. Tabs has the ability to remove tabs as well, by calling removeTabAt(int index) at a given position index. A tab is represented by an index corresponding to the position it was added in, where the first tab has an index equal to 0 and the last tab has an index equal to the tab count minus 1.

If the tab count is greater than 0, then there is always a selected index, which by default is initialized to the first tab. If the tab count is 0, then the selected index is -1.

Tabs has four different tab placement orientations. The default tab placement is set to the TOP location. You can change the tab placement to LEFT, RIGHT, TOP or BOTTOM using the setTabPlacement method.

The following code creates a pane with tab placement of bottom, and places a Label in the center of the first (and only) tab.

Tabs tabs = new Tabs(Tabs.TOP);
tabs.addTab("Tab 1", new Label("I am a Tab!"));
tabs.addTab("Tab 2", new Label("Tab number 2"));
...

TextArea

The text area represents text that might be editable using the system native editor (it might occur in a new screen). The native editor is used to enable complex input methods (such as T9) and application internationalization. The following code creates and initializes the text area:

TextArea textArea = new TextArea(5, 20, TextArea.NUMERIC);

textArea.setEditable(false);

The first two arguments to the TextArea constructor are hints as to the number of rows and columns, respectively, that the text area should display. The third one is a constraint that is passed into the native text editor. Valid values can be one of ANY, EMAILADDR, NUMERIC, PHONENUMBER, URL, or DECIMAL. In addition it can be bitwise OR'd with one of PASSWORD, UNEDITABLE, SENSITIVE, NON_PREDICTIVE, INITIAL_CAPS_SENTENCE, INITIAL_CAPS_WORD. For example, ANY | PASSWORD. The default value is ANY. In the above example NUMERIC only allows the user to type numbers.

Text areas are editable by default. The code setEditable(false) makes the text area uneditable. It is still selectable, but the user cannot change the text area's contents directly.

A 5 x 20 text area is shown in Figure 2-9.

Figure 2-9 Form With Text Area

Description of Figure 2-9 follows
Description of "Figure 2-9 Form With Text Area"

TextField

TextArea doesn't always allow in-place editing on existing devices and doesn't provide "fine grained control" over the input. This allows a text area to be lightweight, and portable for all possible devices. These restrictions sometimes cause a poor user experience because it requires users to go into a different screen for input (since all input is handled natively by the device). From a developer standpoint the native input can be a problem since it doesn't send change events and doesn't provide control over allowed input.

LWUIT provides the TextField component to support direct mobile phone input from within LWUIT. Unlike a TextArea, TextField is completely implemented in LWUIT. Developers can override almost all of its features to provide deep customization (for example, masked input, localization, and more).

TextField inherits the TextArea component and all of its features. It also supports moving to the native text editor.

The constructor also accepts several arguments, similar to the TextArea component.

TextField also has some limitations:

Creating a text field is trivial:

TextField f = new TextField();

Figure 2-10 Sample Text Field

Description of Figure 2-10 follows
Description of "Figure 2-10 Sample Text Field"

Calendar

The LWUIT calendar component allows users to pick a date using a monthly calendar user interface. Use the calendar component to navigate and pick a date, as shown in the following code:

Calendar cal = new Calendar();

Developers can monitor state changes within the calendar using a data change listener or an action listener.

Figure 2-11 Calendar Component

Description of Figure 2-11 follows
Description of "Figure 2-11 Calendar Component"

Tickering

Label (and all its subclasses) includes ticker support. A ticker scrolls the content of a long label across the screen. Ticker ability in labels is usually indicated by displaying three dots "..." after the end of the label. When the label (button, checkbox, etcetera) receives focus, these three dots disappear and the label starts animating like a stock ticker.

A ticker can be started explicitly using a call to startTicker or stopTicker in Label. It can also be prevented by invoking setTickerEnabled(false). To prevent the three dots from appearing at the end of labels or components that support tickering, use setEndsWith3Points(false).

Bidi

BiDi refers to bidirectional language support, generally used for right-to-left (RTL) languages. There is plenty of information about RTL languages (Arabic, Hebrew, Syriac, Thaana) on the internet, but as a brief primer here is a minor summary.

Most western languages are written from left to right (LTR), however some languages are normally written from right to left (RTL). Speakers of these languages expect the UI to flow in the opposite direction, otherwise it seems "weird" just like reading this word in RTL would look: "driew" to most English speakers.

The problem posed by RTL languages is known as bi-directional) and not as RTL since the "true" problem isn't the reversal of the writing/UI but rather the mixing of RTL and LTR together. For example, numbers are always written from left to right (just like in English) so in an RTL language the direction is from right to left and once we reach a number or English text embedded in the middle of the sentence (such as a name) the direction switches for a duration and is later restored.

LWUIT supports BiDi with the following components:

Most of LWUIT's RTL support is under the hood. The LookAndFeel global RTL flag can be enabled using:

UIManager.getInstance().getLookAndFeel().setRTL(true)

(Notice that setting the RTL to true implicitly activates the BiDi algorithm).Once RTL is activated all positions in LWUIT become reversed and the UI becomes a mirror of itself. For example, a softkey placed on the left moves to the right, padding on the left becomes padding on the right, the scroll moves to the left, etcetera.

This applies to the layout managers (except for group layout) and most components. BiDi is mostly seamless in LWUIT but a developer still needs to be aware that his UI might be mirrored for these cases.

Virtual Keyboard

LWUIT supports a lightweight Virtual Keyboard which is implemented with LWUIT's own components. The LWUIT virtual keyboard is used seamlessly where access to the native virtual keyboard isn't possible (for example, MIDP).

Description of vkb.gif follows
Description of the illustration vkb.gif

Customizing the Virtual Keyboard

Since the Virtual Keyboard is a pure LWUIT component it can be customized in various ways.

Changing the Virtual Keyboard Look and Feel

All Virtual Keyboard items can be customized from the resource editor. The associated UI IDs are as follows:

Table 2-1 Virtual Keyboard User Interface IDs

VKB

Customizes the Virtual Keyboard body.

VKBtooltip

Customizes the popup tooltip.

VKBButton

Customizes a regular button on the virtual keyboard (usually a char or a string).

VKBSpecialButton

Customizes the special buttons such as: 'Space', 'SH', etcetera.

VKBTextInput

Customizes the textfield on the virtual keyboard.


Adding a Language

The following example demonstrates how to add an input mode that supports Hebrew.

Adding an Input Mode for Hebrew

  1. Create an array of String arrays in which each array represents a button's column.

    private static final String[][] DEFAULT_HEBREW = new String[][]{
       {"\u05e7", "\u05e8", "\u05d0", "\u05d8", "\u05d5", "\u05df", "\u05dd",
        "\u05e4", "$Delete$"},
       {"\u05e9", "\u05d3", "\u05d2", "\u05db", "\u05e2", "\u05d9", "\u05d7",
        "\u05dc", "\u05da"},
       {"\u05d6", "\u05e1", "\u05d1", "\u05d4", "\u05e0", "\u05de", "\u05e6", 
        "\u05ea", "\u05e5"},
       {"$Mode$", "$Space$", "\u05E3", "$OK$"}
     };
    
  2. Now extend the VirtualKeyboard and make sure the new language mode is added when the VirtualKeyboard is initialized.

    public static class HebrewK extends VirtualKeyboard {
       public HebrewK() {
          addInputMode("˘05d0˘05d1˘05d2", DEFAULT_HEBREW);
          setInputModeOrder(new String[]{"˘05d0˘05d1˘05d2", QWERTY_MODE,
                NUMBERS_SYMBOLS_MODE, NUMBERS_MODE, SYMBOLS_MODE
             });
       }
    }
    
  3. When calling the virtual keyboard, specify the HebrewK class to make it the default:

    VKBImplementationFactory.init(HebrewK.class);

    Description of vkb_hebrew.gif follows
    Description of the illustration vkb_hebrew.gif

Binding a Virtual Keyboard to a TextField

In some cases a TexField should accept only numbers, therefore launching the regular VirtualKeyboard is a mistake. What we need to do is to create a “numbers only” VirtualKeyboard and launch it for a specific TextField.

TextField txt = new TextField();
txt.setConstraint(TextField.NUMERIC);
txt.setInputModeOrder(new String[]{"123"});
txt.setInputMode("123");
 
VirtualKeyboard vkb = new VirtualKeyboard();
vkb.setInputModeOrder(new String[]{VirtualKeyboard.NUMBERS_MODE});
 
VirtualKeyboard.bindVirtualKeyboard(txt, vkb);

Adding Your Own Button to a TextField

There are several use cases where you would want to place your own buttons on a specific Virtual Keyboard. For example if you are asking the user to insert input for a search field you might want a "search" command instead of the regular "ok" command that when pressed automatically invokes a submit action to the network.To accomplish that you must create a new virtual keyboard, declare your own input buttons, and to add your own special button to be part of the virtual keyboard. (By default the Virtual Keyboard understands only the following special keys: "Shift", "Delete", "T9", "Mode", "Space", and "OK").

The following example declares a new input with a new special button "Search".

String[][] SEARCH_QWERTY = new String[][]{
   {"q", "w", "e", "r", "t", "y", "u", "i", "o", "p"},
   {"a", "s", "d", "f", "g", "h", "j", "k", "l"},
   {"$Shift$", "z", "x", "c", "v", "b", "n", "m", "$Delete$"},
   {"$Mode$", "$Space$", "$Search$"}
};
 
VirtualKeyboard vkb = new VirtualKeyboard();
//add the new input mode
   vkb.addInputMode("ABC_S", SEARCH_QWERTY);
   vkb.setInputModeOrder(new String[]{"ABC_S"});
//add the new special button to the vkb
   vkb.addSpecialButton("Search", new Command("Search") {
 
   public void actionPerformed(ActionEvent evt) {
      //search logic...
   }
});
 
//bind the vkb to the textfield
VirtualKeyboard.bindVirtualKeyboard(txt, vkb);
f.addComponent(txt);
Description of vkb_search.gif follows
Description of the illustration vkb_search.gif