USER INTERFACE


Overview

The following chapters will introduce you to the main aspects of user interface in TotalCross, including graphical interface controls and events support.

 User Interface styles

List of types

TotalCross has five look-and-feel types of user interfaces:
The style can be switched to by using MainWindow.setUIStyle(int type), and it is platform-idenpendent (can be used in any device of any platform). Here is an example of use:
public class Foo extends MainWindow
                        {
                         public Foo()
                         {
                          super("Hi bar", TAB_ONLY_BORDER);
                          setUIStyle(Settings.Android);
                      }
                  }
              
The decision of which user interface to use must be made in the main window’s constructor. If nothing is changed, Vista with a blue background is used. Changing the user interface outside the main window’s constructor can crash your application. If you try to change it more than once, a RuntimeException will be thrown. The other possible values to type are: Settings.Flat, and Settings.Vista.
In the pictures below you can see snapshots of the of the old UIGadgets sample running on JDK using different resolutions and user interface styles. After each picture you’ll find the command line options provided to the launcher on each case:


figure companion_resources/images/companion_UIGadgets_Android.png figure companion_resources/images/companion_UIGadgets_iPhone.png
/scr android /uiStyle android:

Android (320x480x16)
/scr iPhone: iPhone (320x480x24)
figure companion_resources/images/companion_UIGadgets_Win32.png
/scr Win32: Windows 32 (240x320x24)


figure companion_resources/images/companion_UIGadgets_uiStyleFlat.png figure companion_resources/images/companion_UIGadgets_uiStyleVista.png
/uiStyle Flat: Flat user interface style /uiStyle Vista: Vista user interface style
figure companion_resources/images/companion_UIGadgets_bbStorm.png
/penlessDevice: Acts as a device without touch screen. (notice the highlighted control)

Support for devices without pen

The iOS and Android platforms introduced the use of finger instead of pen (however, some new Android works better with pens than with finger, such as some devices with barcode scanner). A finger is much less precise than a pen, thus an algorithm is used to locate the closest control. These platforms also introduced the concept of drag and flick: drag means that you placed your finger in the screen and moved it while pressed, and flick means that you suddenly lifted the finger, to continue the scroll even while your finger is up. The scroll then slows down until a complete stop or if you press the finger again.
TotalCross 1.3 added support for this, activated when you set the user interface style to Android or when making Settings.fingerTouch = true.
The following controls supports flicking: button menu, grid, list box, list container, multi edit, scroll container (and its subtypes), tabbed container, and tree.
When fingerTouch is true, controls that can be flicked replace the scroll bar by a scroll position control, which only appears while the control is being scrolled or flicked.

 Font Support

To keep the user interface consistent across different platforms, TotalCross applications uses its own font types instead of using the device’s font type. The basic font type chosen for TotalCross is the Tahoma font, included on the SDK as the TCFont.tcz file. It contains fonts with no size limit, regular and bold.
Unicode fonts are not included in the default font file!
The base size of the application’s font is defined as Font.NORMAL_SIZE, which is a constant initialized at runtime based on the screen resolution. This way you may select another size by using a relative value, like Font.NORMAL_SIZE+2 (which is equal to Font.BIG_SIZE), and the font will be correctly scaled among different resolutions. The constants Font.MIN_FONT_SIZE and Font.MAX_FONT_SIZE have the minimum and maximum font size, respectively. Their default values are 7 and 80 (48 for Windows 32), respectively, but can be changed.
Finally, Font.TABSIZE is the number of spaces that will drawn when a tab character is found by the VM. You can define the number of spaces that will be drawn setting this field. It defaults to 3, but you can change it at any time.
To create your own font files you may use the FontGenerator (included in the tc.jar). It creates a compressed file with your own set of bitmap fonts, and supports anti-aliased fonts, which makes the font appear rounded and improves legibility. The created font must be based on the TrueType fonts.
Some usage examples (here we assume the tc.jar is in the classpath):
To see if the font you created is installed on the target device, query its name after the creation. If the font is not found, its name is changed to match the default font. When the parameter /rename: is used with TCFont, the default font is changed to the new created font.
The default font name used is stored in Font.DEFAULT.
Read totalcross.ui.font.Font JavaDoc for more information. Check also totalcross.
ui.font.FontMetrics
.

 The MainWindow class

Every TotalCross program must have one and only one class that extends totalcross.ui. MainWindow. It is the interface between the VM and the TotalCross program: it receives all events and dispatches them.
import totalcross.ui.*;
            ​
            public class Foo extends MainWindow
            {
             public Foo()
             {
              super("Hi handheld world", HORIZONTAL_GRADIENT);
              gradientTitleStartColor = Color.getRGB(88, 130, 239);
              gradientTitleEndColor = Color.getRGB(10, 36, 106);
              titleColor = Color.WHITE;
          }
          ​
          public void initUI()
          {
              // add controls here
          }
          ​
          public void onExit()
          {
              // close stuff here
          }
      }
  
The VM first calls the MainWindow default constructor (in this case, Foo()) and after that it enqueues a timer event, which will then call the initUI() method (inherited from the class Container). You must initialize all the user interface in the initUI() method. Initializing the user interface on the constructor might crash the application, and some operations can only be performed after the MainWindow’s initUI() method is reached.
The onExit() method is called when the VM exits under normal circumstances , i.e., if the user closes the application or the programmer ends the application by using exit() or exec(), or even when the application is halted by an unhandled exception. However, under abnormal circumstances where a fatal error occurs, reseting the device, the onExit() method is not called. When this is called, all threads are already killed.
To change the font used by all controls created, you must call the method setDefaultFont() on the first line of the MainWindow’s constructor.
If you’re going to set the MainWindow’s title and/or style, you should use super(title, style) instead of the methods setTitle() and setBorderStyle() to improve performance. However, you can’t use super() and setDefaultFont() together because both must be the on first line of the constructor. That means you’ll have to use setTitle() and setBorderStyle() instead of super(title, style) to be able to use setDefaultFont().
The style can be: Window.NO_BORDER, Window.RECT_BORDER, Window.ROUND_BORDER, Window.TAB_BORDER, or Window.TAB_ONLY_BORDER.

The Application lifecycle

The application on TotalCross has a predefined life cycle, handled by methods defined in MainWindow:
  1. initUI(): called when the application starts.
  2. onMinimize(): called when the user press the home key, or when a call is received, or when the screen turns off. On Android and Windows 32, the application execution is not paused. On Windows Phone 8 and iOS, it is paused.
  3. onResume(): called after the call ends, the screen is turned on again, or the program was exited softly on Android. It is also called again if the user clicks on the application icon on Android and iOS. On WP8, it is necessary to press back in the main menu and click on the opened application. Clicking on its icon in the list of applications will kill the current instance and relaunches it again.
  4. onExit(): called when the system decides that is time to finish the application. If the home key was pressed, this method is called when another TotalCross application is launched on Android if the application is not installed as a single package.
If the user press the home key and then forces the application to stop (by going to the Settings / Applications) on Android and iOS, then all Litebase tables may be corrupted (actually, no data is lost, but a TableNotClosedException will be issued). So, it’s a good thing to call
LitebaseConnection.closeAll()
in your Litebase instances in the onMinimize() method and recover them in the onResume() method. Just remember that all prepared statements, row iterators and result sets will be invalid and can’t be reused. Notice that the application might also be killed by the system if it’s on background.
On WP8, there is no way to kill an application. To kill it, you must restore it pressing back in the main menu and them openning the application again. Then, press back until finishing the application.
It is also a good practice to save all necessary data and application state so that the when the user goes back to the application it won’t need to do a task again, such as entering data again in a form which was lost when the application was closed by the system. Of course there are situations where the user must retype data, such as login and password and when using bank applications.
Remember that applications for Android, iOS, and Windows Phone 8 shouldn’t have an exit button or an exit option in the menu. The application should be designed to be opened all the time and only the system should close it when needed. Again, there are exceptions, for example when the user doesn’t agree with an eula and the application can’t continue running.
Finally, it is a good idea to map the device back key on Android and WP8 to go back to the last window/menu used. Just remember that on WP8 back is back, you just can use it to go back to the last screen used. On the first screen, back should exit the application. The only exception are games, where back during a game play goes to the pause window.
To know more detais about totalcross.ui.MainWindow, read its JavaDocs.

 Adding Controls

The class totalcross.ui.Control is the base class of all user interface controls, like buttons and labels.
Controls must be added to a Container or one of its subclasses, like MainWindow. This container is referred as the parent of the control. To set the control bounds in the container, you can use the method setRect(x,y,width,height).

Relative positioning

TotalCross lets you place controls in two ways:
The hard and wrong way, by setting the control bounds with numbers.
E.g.: control.setRect(10,10,80,12);
The smart way, by using constants for relative coordinates. The idea of the relative positioning is to let the programmer concentrate mainly on the position and let the sizes be computed automatically. The constants are:

Coordinate X

LEFT places the control at the position 0 horizontal. If the parent is a Window, aligns the control at the left of the window’s client rect.
RIGHT aligns the control at the right. If the parent is a Window, aligns the control at the right of the window’s client rect (relative to the screen).
RIGHT_OF aligns the control at the right of the last control (relative to a control).
CENTER centers horizontally the control in the container (relative to the screen).
CENTER_OF centers horizontally based on the last control’s width (relative to a control).
BEFORE places the control before the last control added.
AFTER places the control after the last control added.
SAME places the control at the same x coordinate of the last control added.
KEEP keeps the last position used. To be used with WILL_RESIZE.

Coordinate Y

TOP places the control at position 0 vertical. If the parent is a Window, aligns the control at the top of the window’s client rect.
BOTTOM places the control at the bottom of the container. If the parent is a Window, aligns the control at the bottom of the window’s client rect.
CENTER centers vertically the control in the container.
CENTER_OF centers vertically based on the last control’s height.
BEFORE places the control before the last control added.
AFTER places the control after the last control added.
SAME places the control at the same y coordinate of the last control added.
BOTTOM_OF aligns the control at the bottom of the last control.
KEEP keeps the last position used. To be used with WILL_RESIZE.

Width

PREFERRED lets the control determine its best width. This is normally computed using the control’s text width in the selected font.
FILL the control’s width will fill the space left until the end of the container. Cannot be used with RIGHT/CENTER.
SAME sets the control’s width with the same width of the last control added.
FIT sets the control’s width to fit between the specified x position and the last control added x position. For example, if you place a label at LEFT, a button at RIGHT and want to place an edit between those two controls, use FIT as the control’s width using the Label as relative control.
SCREENSIZE computes the width as a percentage of the screen’s size (width). The percentage is passed as a number with + sign. E.G.: SCREEN_SIZE+20 will take the width as 20% of the screens size. Note that the size will change when the device is rotated.
WILL_RESIZE sets that the width will be resized later, when all controls were added. You cannot use RIGHT or CENTER for placing controls when using WILL_RESIZE. After all items were added, call the resizeWidth() method.
KEEP keeps the last position used. To be used with WILL_RESIZE.
PARENTSIZE computes the width as a percentage of the parent control size (will use parent’s width). If the parent is unknown, the screen size will be used instead.
SCREENSIZEMIN uses screen’s minimum size between width and height.
SCREENSIZEMAX uses screen’s maximum size between width and height.

Height

PREFERRED lets the control determine its best height. This is normally computed using the control’s text height in the selected font.
FILL the control’s height will fill the space left until the end of the container. Cannot be used with BOTTOM/CENTER.
SAME sets the control’s height with the same height of the last control added.
FIT sets the control’s height to fit between the specified y position and the last control added y position. For example, if you place a button at TOP, a label at BOTTOM, and want to place a list box between both, use FIT as the control’s height using the button as relative control.
SCREENSIZE computes the height as a percentage of the screen’s size (height).
WILL_RESIZE sets that the height will be resized later, when all controls were added. You cannot use BOTTOM or CENTER for placing controls when using WILL_RESIZE. After all items were added, call the resizeHeight() method.
KEEP keeps the last position used. To be used with WILL_RESIZE.
PARENTSIZE computes the height as a percentage of the parent control size (will use parent’s height). If the parent is unknown, the screen size will be used instead.
SCREENSIZEMIN uses screen’s minimum size between width and height.
SCREENSIZEMAX uses screen’s maximum size between width and height.
  • Before calling setRect(), the control must be added to the container and have its characteristics (like font, border type, etc) set. This is needed because the control position is computed based on its parent container and the control’s size is computed based on its characteristics. And all this is computed at setRect().
  • The control’s coordinates are always relative to its parent coordinates.
  • If you use LEFT/TOP/RIGHT/BOTTOM with the first control added to a window, it will use the coordinates of the window’s client rect, which are the container’s area excluding the title and the borders, if any.
  • You cannot use FIT in both width/height. It won’t work as expected because you can’t specify two controls to make it relative to. The width/height is always related to the last control added.
  • See the sources for the controls ColorChooserBox, NumericBox, and TimeBox to learn how to use WILL_RESIZE.
The use of relative positioning is highly recommended. It makes the program portable between different resolutions and fonts.

Making UI adjustments

The constants described above have one important feature: a variable or a number can be used to increment/decrement the result value. Examples: CENTER+2, BOTTOM-5, PREFERRED+4, FILL+2, BEFORE-5. This value cannot be higher than 5, otherwise your interface will not be properly shown in other resolutions. Using something like LEFT+10 or BOTTOM-15 is as bad as using absolute values.
However, these values suffer a problem: a pixel’s size may vary depending on the screen’s density (also known as DPI). So, 4 may be good at a 240x320 screen, but too small in a 600x1024 tablet.
To bypass these limitations, we introduced a way to compute that adjustment based on the current’s font size instead of a fixed pixel value. To enable it, you must set the following property at the application’s static initializer:
Settings.uiAdjustmentsBasedOnFontHeight = true;
After doing this, the adjustment you make will be a percentage of the font’s height. So, AFTER+50 is AFTER+(50% of font’s height), PREFERRED+20 is PREFERRED+(20% of font’s height), and so on.
However, this feature is not supported by all controls. To disable this feature for a particular control the property uiAdjustmentsBasedOnFontHeightIsSupported is set to false in the class constructor.
The controls can be traversed using the 5-way navigation present on most PDAs and Smartphones. It is automatically activated on penless devices, but can be activated on pen devices by setting the property Settings.keyboardFocusTraversable to true. Controls are traversed according to the order of elements in the field Container.tabOrder. The controls are added to the vector in the order as they are added to the container. This may not be optimal; you may assign a new order by adding the controls to the vector:
this.tabOrder = new Vector(new Object[]{ed1,btn1,btn2,ed2});

Useful members

More details and more members can be found in the totalcross.ui.Control JavaDoc.
The last four methods are useful when you’re adding controls that do not need to have any of its characteristics (like font or border) changed. Changing the control’s characteristics after those methods will give you unpredictable results. This happens because the control does not reposition/resize itself when you change its characteristics (just as an example, suppose that the default font has 11 in height, and you add the control; then you change the font to one with height 22; the control will not be resized and you’ll see only half of the text).
getForeColor() and getBackColor() returns the color depending if the control’s state is enabled or disabled.

 Events

Events represent all activity that goes on between the user and the application. When the user interacts with a program, the VM creates an event representing the action and communicates these actions to the programs using events.
This chapter is organized into the following sections to provide a quick start on event handling in TotalCross:
Control Events briefly explains the basic types of events handled by controls.
Handling Events explains the event-handling models available in TotalCross.
The Event class describes this class in more detail.
If you’re new to TotalCross and want to get things started quickly, skip the Delegation Event Model in section two – “Handling Events”.
If you’re familiar with TotalCross and wants to know more about events, make sure you understand both event-handling models.

Control Events

There are two basic types of events: pen events and key events. These events are handled by the window, which creates a new event of the proper type (pen event or key event) and forwards it to the target control. These events are handled by the control, which may convert them to other events, defined on the class ControlEvent.
Below we can see how each event defined on ControlEvent is handled by each control:
CURSOR_CHANGED event sent when user calls Edit.setCursorPos().
PRESSED this event is posted by controls when they receive a PEN_DOWN (like check, radio, tab panel), and a PEN_UP (button, list box, push button group, scrollBar) or even a
WINDOW_CLOSED
(comboBox).
FOCUS_IN and FOCUS_OUT posted by the window when a control different from the current one is clicked. The FOCUS_OUT is first posted to the old control, and the event FOCUS_IN is then posted to the new control.
TIMER this is a special event that is posted to the control that has a timer assigned to it; it is called when the timer countdown has reached zero.
WINDOW_CLOSED posted by the unpop method to notify all controls that a window has been closed. Some controls, like combo box, has a pop list assigned to it; when the pop list issues a WINDOW_CLOSED event, the combo box receives it and converts to a PRESSED event.
SIP_CLOSED The event type fot the SIP being closed by the system. Works on Android and iOS. The application cannot see this event since it is interpected by the topmost window.
HIGHLIGHT_IN and HIGHLIGHT_OUT these events are posted by the window when the user changes the focus to another control and the field Settings.
keyboardFocusTraversable
is set to true. The HIGHLIGHT_OUT event is first posted to the old control, and the event HIGHLIGHT_IN is then posted to the new control.
Take a look at totalcross.ui.event.ControlEvent JavaDoc for more details.
Some controls have its own event class. They are Animation, Grid, and ListContainer. Take a look at totalcross.game.AnimationEvent, totalcross.ui.event.GridEvent, and totalcross.ui.event.ListContainerEvent JavaDocs for more details about their respectively event classes.
Take a look also at totalcross.ui.event.EnabledStateChangeEvent JavaDocs. This class represent an event generated when the enabled status of a control changes. This will occur when the method setEnabled() is issued.

Event Handling

TotalCross implements two event-handling models.

Inheritance Event Model

Similar to the Java 1.0 event model, this approach requires you to subclass UI components and override the event handling method – onEvent(Event e) – in order to catch and process UI events. When a control posts an event (using the postEvent() method) it is propagated sequentially up the UI hierarchy until it is either consumed, or the root of the hierarchy is reached.
If we have a button inside a tab panel in a window, and this button receives an event, the event is propagated up the hierarchy:
Window.onEvent()
TabPanel.onEvent()
Container.onEvent()
Button.onEvent()
After handling the event, you can break the event propagation by setting the Event.consumed field to true.
Here’s a simple example:
public class MyProgram extends MainWindow
            {
             Button pushB;
             ​
             public void initUI()
             {
              add(pushB = new Button("Push me\nPlease"), CENTER, TOP);
          }
          ​
          public void onEvent(Event event)
          {
              switch (event.type)
              {
               case ControlEvent.PRESSED:
               if (event.target == pushB)
               // handle pushB being pressed
               break;
           }
       }
   }
  • Disabled controls can only post TIMER events. The method postEvent() returns immediately if the control is not enabled and the type of the event received is not TIMER. The only exception to this occurs on fingertouch devices, to allow the flick stop or start when a PEN_DOWN occurs in a disabled control.
  • The event propagation stops if the control is moved to another container. For example, when you pop up the keyboard, the target edit is removed from its parent and added to the keyboard window; at this time, the event propagation (of the key event) stops.
  • The MainWindow does not receive an event posted by a control in a popup window. The only exception for this is the WINDOW_CLOSED, which is posted to the window that popped it.
  • A control that is not added to a container (or any parent of its container is not added to a window) will never receive events nor be repainted.
Small programs can handle the events by implementing the onEvent() method in the
MainWindow
class, but it can become confusing if the program gets bigger. An alternative is to create classes that extend Container and swap them on the MainWindow as the user navigates through the program. Each class implementing the onEvent() method will have to handle its own events.

Delegation Event Model

Similar to the event model introduced by Java 1.1, but this approach solves some limitations of the Inheritance Event Model, which are:
In this model, an event is propagated from a “source” object to a “listener” object by invoking a method on the listener. and passing in the instance of the event subclass, which defines the event type generated.
A listener is an object that implements a specific EventListener interface. An
EventListener
interface defines one or more methods which are to be invoked by the event source in response to each specific event type handled by the interface.
An event source is an object which originates events. The source defines the set of events it emits by providing a set of add<EventType>Listener(<EventType>Listener) methods which are used to register specific listeners for those events.
Here’s the same example, using an EventListener() instead of overriding onEvent():
public class MyProgram extends MainWindow
            {
             Button pushB;
             ​
             public void initUI()
             {
              add(pushB = new Button("Push me\nPlease"), CENTER, TOP);
              pushB.addPressListener(
              new PressListener()
              {
                public void controlPressed(ControlEvent e)
                {
                 // handle pushB being pressed
             }
         }
         );
     }
 }
Creating listeners using the new <EventType>Listener, as indicated above, makes your program bigger and should be used with care. If you will add listeners of the same event type to many controls, implement the listener in the class like this:
public class MyProgram extends MainWindow implements PressListener

The Event class

Let’s now look at the details of each event class. TotalCross has ten event classes in the totalcross.
ui
package: the already described ControlEvent, AnimationEvent, GridEvent,
ListContainerEvent
, EnabledStateChangeEvent; and MediaClipEvent, KeyEvent, PenEvent, ScanEvent,
TimerEvent
, and UIRobotEvent. Their parent class is Event, which provides some useful members:
Be careful with the timestamp. There is no way to convert it to the current hh:mm:ss:millis. It is just useful for comparison purposes; or to compute the time elapsed since the last event occurred. You can use it to simulate a double-click, by checking the elapsed time between two clicks.
To keep memory usage low, some VM routines reuse PenEvents and KeyEvents objects; so, if you just save a reference to the object instead of the timestamp itself, you may get unexpected results.
The Event class has also a static method called getNextAvailableEventId() to avoid conflicts when your application or library creates a new Event type.
For more detais about the totalcross.ui.event.Event class, take a look at its JavaDoc.
The event classes that have not been described before are:

PenEvent

PenEvent is a pen down, up, move, or drag event. A pen drag occurs when the pen moves while the screen is pressed. For more detais about the totalcross.ui.event.PenEvent class, take a look at its JavaDoc.

KeyEvent

A KeyEvent is a key press event. The key field is the key pressed or entered by other means (grafitti input). This is either a normal character key (if the value is < 70000, values from the ASCII table) or one of the special keys defined in the DeviceKeys interface.
Some of the keys defined in totalcross.sys.SpecialKeys need a special code to be manipulated: they are not handled by the application unless the application requests it. For example, the totalcross.sys.SpecialKeys.UP and totalcross.sys.SpecialKeys.DOWN are automatically sent to the application’s event queue, but the SpecialKeys.KEYBOARD_* and SpecialKeys.HARD*, not. To be able to intercept these keys, you must use the method Vm. interceptSpecialKeys(mask).
The SpecialKeys interface does not have all possible keys mapped. If you have a particular device, you can learn the code of a key by creating a test application and calling Vm.showKeyCodes(boolean on). When this mode is on, each time a key is pressed, the VM shows an alert with the code. Then use this key code in the Vm.interceptSpecialKeys().
For more detais about the totalcross.ui.event.KeyEvent class, take a look at its JavaDoc.

MediaClipEvent

This class represents the events posted by a soundclip control. For more detais about the totalcross.
ui.media.MediaClipEvent
class, take a look at its JavaDoc.

ScanEvent

ScanEvent is an event thrown by the barcode scanner. Used in the Scanner class. For more detais about the totalcross.io.device.scanner.ScanEvent class, take a look at its JavaDoc.

TimerEvent

TimerEvent represents a control’s timer. Timers are created and destroyed using the addTimer() and removeTimer() methods present in the Control class. For more detais about the totalcross.
ui.eventTimerEvent
class, take a look at its JavaDoc.

UIRobotEvent

Event sent when a robot runs. The target is always the MainWindow’s instance. For more detais about the totalcross.unit.UIRobotEvent class, take a look at its JavaDoc.

Listener Interfaces

This subsection lists the interfaces used to add listeners to use the delegation event model. All of them are in the package totalcross.ui.event. For more details about them, take a look at their JavaDocs.

 Basic Controls

In this chapter we will learn the details of all basic controls in the package totalcross.ui: button, edit, label, check, radio, radio group controller, combo box, list box, multi edit, grid, and tooltip.
Each control can have its font, foreground/background colors and state (enabled/disabled) set. Their look depends on the look-and-feel set on the MainWindow constructor (Vista is the default).
For each control we’ll see its characteristics, how to create them with the provided constructors, and how to handle their events.
You can see most of the user interface controls available in TotalCross looking at the ui package from the TotalCrossAPI sample.
Remember you must set the characteristics of the controls before calling setRect()/add() to set their bounds.

Buttons

last update: 07/05/2018

Overview

Buttons are an essential way to interact with and navigate through an app, and should clearly communicate what action will occur after the user taps them, like invoke an action to confirm [ok] or cancel [cancel] something. The Buttons can consist of text and/or icon/image, and can be enhanced with a variety of attributes. Here is a sample with some buttons using the Material Design style from Google (now inside the UI package from the TotalCrossAPI sample):

In order to be more intuitive and to be as Java is not appropriate, the Button object must be instantiated in this way:

Button button = new Button("text");

Usage Examples

Scroll Container sc = new ScrollContainer(false, true);
add(sc,LEFT,TOP,FILL,FILL);

//Simple Button
Button simpleButton= new Button("Simple Button");
simpleButton.setBackForeColors(0x0087c8, Color.WHITE);
sc.add(simpleButton,LEFT+50 , AFTER+50, PREFERRED+55, DP+60);

//Multi Line Button (simple size)
Button multiLineButton= new Button("This is\na multi-line\nButton");
multiLineButton.setBackForeColors(0xAED581, Color.WHITE);
sc.add(multiLineButton, LEFT+50, AFTER+50, PREFERRED+50, DP+90);

// Full Button
Button fullButton = new Button("Full button");
fullButton.setBackForeColors(0x0087c8, Color.WHITE);
sc.add(fullButton, LEFT+50, AFTER+50, FILL-50, DP+65);

//Image Button
Image img = Resources.warning.getSmoothScaledInstance(fmH, fmH);
img.applyColor2(Color.WHITE);

imageButton= new Button("This is an image Button", img, RIGHT, 0);
imageButton.setBackForeColors(0xEF5350, Color.WHITE);
sc.add(imageButton, LEFT+50, AFTER+50, FILL-50, DP+65);

// Multi Button
MultiButton simpleMultiButton= new MultiButton(new String[]{"Option One","Option Two"});
sc.simpleMultiButton.setBackForeColors(Color.ORANGE, Color.WHITE);
add(simpleMultiButton, LEFT+50 , AFTER+50 , FILL-50 , DP+65);
MultiButton multiButton= new MultiButton(new String[]{"Left","Center","Right"});
simpleMultiButton.setBackForeColors(0xce93d8, Color.WHITE);
sc.add(multiButton, LEFT+50 , AFTER+50, FILL-50, DP+65);
//Transparent BackColor Button
Button transparentButton= new Button("TransparentBackColor Button");
transparentButton.transparentBackground = true;
sc.add(transparentButton, LEFT+50 , AFTER+50, FILL-50, DP+65);

To see the full example click here.

To see the tutorial click here.


Edit

Edit is a control used to get text input when the user types using the keyboard or the grafitti area. It allows you to select text and cut/copy/paste it. Here are a screenshot from some edits using the Material Design style from Google (now inside the ui package from the TotalCrossAPI sample):
Here are some other features:
Sample code:
public void initUI()
            {
             Edit ed1 = new Edit();
             add(ed1, LEFT, TOP+5, FILL, PREFERRED);
             ​
             Edit ed2 = new Edit("9999999999999");
             ed2.setDecimalPlaces(4);
             ed2.setMode(Edit.CURRENCY,true);
             add(ed2, RIGHT, AFTER+5);
             ​
             Edit ed3 = new Edit("99/99/9999");
             ed3.setMode(Edit.DATE);
             add(ed3, LEFT, SAME);
             ​
             Edit ed4 = new Edit("AAAAA");
             ed4.setMode(Edit.PlainORD);
             add(ed4, LEFT, AFTER+5);
             ed4.setText("pass");
             ​
             Edit ed5 = new Edit(""); // use FILL as preferred width
             ed5.setMaxLength(4);
             ed5.setValidChars("123ABC");
             add(ed5, LEFT, AFTER+5);
             ​
             Edit ed6 = new Edit("Can’t Edit");
             ed6.setEditable(false);
             add(ed6, LEFT, AFTER+5);
         }
     
The Edit control posts a ControlEvent.PRESSED event when the text changes. You may also want to intercept the event ControlEvent.FOCUS_OUT to validate the edit’s text.
For more information, check the totalcross.ui.Edit JavaDoc.

Label

This control is used to display static text or a marquee. The label in TotalCross can also display multiple lines of text, separated by the character \n. A label never receives focus neither dispatches events. Here is a screenshot from a multi-lined label using the Android style from the old UIGadgets sample:
figure companion_resources/images/label_001.png
Here are some other features:
Sample code:
public void initUI()
            { 
             add(new Label("This is a simple label"), LEFT, TOP);
             ​
             Label lab1 = new Label("This is a centered label", CENTER);
             add(lab1);
             lab1.setRect(LEFT, AFTER, FILL, PREFERRED);
             ​
             Label lab2 = new Label("This is another centered label", CENTER);
             add(lab2);
             lab2.setRect(LEFT, AFTER, FILL, PREFERRED);
             ​
             Label lab3 = new Label("Wow! A wonderful 3D label!");
             lab3.set3d(true);
             add(lab3, LEFT, AFTER);
             ​
             Label lab4 = new Label("A beautiful inverted label");
             lab4.setInvert(true);
             add(lab4, LEFT, AFTER);
             ​
             Label lab5 = new Label("This is a very long\ntext and i dont\nwant to waste my\ntime parsing it to\nbe fit it!");
             add(lab5);
             lab5.setRect(CENTER, AFTER, PREFERRED, PREFERRED);
         }
     
For more information, check the totalcross.ui.Label JavaDoc.

Check

Check is a control that has a rectangle with a check inside and a text at right, and is used for items that have an on/off state. When it is on, the check box is marked; otherwise, it is unmarked.
Here are some screenshots from some checks using the Android style from the old UIControls sample (now inside the ui package from the TotalCrossAPI sample):
Here is an example showing a check being used followed by some properties:
public class MyProgram extends MainWindow
            {
             Check check;
             ​
             public void initUI()
             {
              add(check = new Check("Check me"), LEFT, AFTER);
          }
          ​
          public void onEvent(Event event)
          i
          if (event.type == ControlEvent.PRESSED && event.target == check)
          {
           bool checked = check.isChecked();
           // ... handle check being pressed
       
Sample code:
public void initUI()
            {
             Check chk1 = new Check("Checked enabled");
             add(chk1, LEFT, TOP+5);
             chk1.setChecked(true);
             ​
             Check chk2 = new Check("Unchecked enabled");
             add(chk2, SAME, AFTER+5);
             ​
             Check chk3 = new Check("Check disabled");
             add(chk3, SAME, AFTER+5);
             chk3.setChecked(true);
             chk3.setEnabled(false);
         }
     
Like the button control, the only event that the check control posts is the ControlEvent. PRESSED. Below we see an example of how to handle a click on the check:
public void onEvent(Event event)
            {
             switch (event.type)
             {
               if (event.target == chk1)
               {
                String state = chk1.isChecked()? "checked" : "unchecked";
                new MessageBox("TotalCross", "Checkbox " + state).popup();
            }
            break;
        }
    
For more information, check the totalcross.ui.Check JavaDoc.

Radio Button

last update: 13/07/2018

Overview

A radio button is a button that can be either checked or unchecked. A user can tap the button to check or uncheck it. It can also be checked from the template using the checked property.

Use an element with a RadioGroupController attribute to group a set of radio buttons. When radio buttons are inside a [radio group](link para a documentação do radio-group), just one radio button in the group can be checked at any time. If a radio button is not placed in a group, they will all have the ability to be checked at the same time.

Usage

// Creating a simple radioButton with checked checked in the class itself
Radio radio= new Radio("RadioButton");
radio.setChecked(true);
add(radio, LEFT+100, TOP+100 ,PREFERRED+100,PREFERRED+25);

// Creating a simple radioButton
Radio radio2 = new Radio("RadioButton");
add(radio2, LEFT+100, AFTER+50 ,PREFERRED+100,PREFERRED+25);

// Creating RadioButton with background Color
Radio bcolor = new Radio("Background Color");
bcolor.setBackColor(Color.YELLOW);
bcolor.textColor = Color.BLUE;
bcolor.checkColor = uiMaterial ? Color.BLACK : Color.YELLOW;
add(bcolor, LEFT+100, AFTER+50 ,PREFERRED+100,PREFERRED+25);

// Creating RadioButton with foreground Color
Radio fcolor = new Radio("Foreground Color");
fcolor.setForeColor(Color.darker(Color.GREEN));
fcolor.checkColor = Color.GREEN;
add(fcolor, LEFT+100, AFTER+50 ,PREFERRED+100,PREFERRED+25);

// Creating dependency relation between radioButtons
final Radio enable = new Radio("Enable: ''Never'' ");
enable.setChecked(true);
add(enable, LEFT+120, AFTER+100 ,PREFERRED+100,PREFERRED+25);

final Radio never = new Radio("Never", radioGroup2);
add(never, LEFT+100, AFTER+50 ,PREFERRED+100,PREFERRED+25);
enable.addPressListener(new PressListener(){
 public void controlPressed(ControlEvent e){
  boolean b = enable.isChecked();
  never.setEnabled(b);
 }
});

Radio Group Controller

last update: 13/07/2018

Overview

A radio group is a group of radio buttons. It allows a user to select at most one radio from a set. Checking one radio button that belongs to a radio group unchecks any previous checked radio button within the same group.

Usage

//Creating a RadioGroup
RadioGroupController radioGroup = new RadioGroupController();
//assigning RadioButtons to the RadioGroup
Radio radio = new Radio("RadioButton", radioGroup);
add(radio, LEFT+100, AFTER+100 ,PREFERRED+100,PREFERRED+25);

ComboBox and ComboBoxDropDown

The combo box is a very useful control to display a list of items where only one can be selected. It consists of a text with a button and a ComboBoxDropDown control that is popped up when the button is pressed. The popped up list is closed when one of its items is selected or the control loses the focus.
Here are a screenshot from the combo box using the Material Design style from Google (now inside the ui package from the TotalCrossAPI sample) Note that below the combo box component, there is a list box:
Another combo box from the old sample UIGadgets, also using Android style, can be seen here, where the left combo box has a attached MultiListBox, which extends ListBox and lets the user select more than one item:
figure companion_resources/images/combo_005.png figure companion_resources/images/combo_006.png
figure companion_resources/images/combo_007.png
figure companion_resources/images/combo_008.png figure companion_resources/images/combo_009.png
Sample code:
public void initUI()
            { 
             String []items1 = {"","Orange","Apple","Grape","Lemon"};
             String []items2 = {"One","Two","Three", ...};
             String []items3 = {"Disabled","Enabled"};

             ComboBox cb1 = new ComboBox(items1);
             add(cb1,LEFT,TOP+5);
             ​
             ComboBox cb2 = new ComboBox();
             cb2.add(items2);
             cb2.add("Twenty one");
             add(cb2,RIGHT,AFTER+5);
             ​
             ComboBox cb3 = new ComboBox(items3);
             add(cb3);
             cb3.setRect(LEFT,BOTTOM,PREFERRED+4,PREFERRED);
             cb3.setSelectedIndex(0);
             cb3.setEnabled(false);
         }
     
As the preceding controls, this one also posts a ControlEvent.PRESSED when the user selects an item.
public void onEvent(Event event)
            {
             switch (event.type)
             {
              case ControlEvent.PRESSED:
              if (event.target == cb1)
              new MessageBox("TotalCross", "Item selected: " +  cb1.getSelectedItem()).popup();
              break;
          }
      }
  
For more information, check the totalcross.ui.ComboBox JavaDoc.

ListBox

The list box is a control that allows the user to select one item from a list contained within multiple line text box. It looks like an open combo box (in fact, the combo box uses the list box control). Consider using the list box instead of the combo box if the screen has enough space available to show all items.
Here are a screenshot from a simple list box using the Material Designs style from Google (now inside the ui package from the TotalCrossAPI sample). Note that above the list box component, there is a combo box:
Here is an example showing how it can be used:
public class MyProgram extends MainWindow 
            {
             ListBox lb;
             ​
             public void initUI()
             {
              lb = new ListBox();
              add(lb);
              lb.add(new String[]{"Daniel","Jenny","Helge","Sandra"});
              lb.add("Marc"); // you may set the rect by using PREFERRED only after the items were added.
              lb.setRect(LEFT, TOP, PREFERRED, PREFERRED); // use control’s preferred width based on the size of the elements
          }
          ​
          public void onEvent(Event event)
          {
              switch (event.type)
              {
               case ControlEvent.PRESSED:
               if (event.target == lb)
               Object element = lb.getSelectedItem(); // in most cases, this is just a String and may be casted to such
           }
       }
   } 
Please notice that TotalCross’ list box does not allow the selection of multiple items like one would expect. If you need this feature, use the MultiListBox control (refer to the advanced controls section).
Sample code:
public void initUI()
            {
             String[] items1 = { "", "Orange", "Apple", "Grape", "Lemon" };
             String[] items2 = { "One", "Two", "Three" };
             String[] items3 = { "Disabled", "Enabled" };
             ​
             ListBox lb1 = new ListBox(items1);
             add(lb1, LEFT, TOP + 5);
             ​
             ListBox lb2 = new ListBox();
             lb2.add(items2);
             lb2.add("Twenty one");
             add(lb2);
             lb2.setRect(RIGHT, AFTER + 5, PREFERRED, FILL - 5);
             ​
             ListBox lb3 = new ListBox(items3);
             add(lb3, RIGHT, TOP + 5);
             lb3.setEnabled(false);
         }
     
Be careful when setting the items with an object array. The array is assigned as is, no copy is made. So, if you use the same array in another control and an item inside the array is changed, this change will reflect in both controls. However, if you add a new item, a new array is created to store the added item and the program works correctly. The best practice is to have one array for each list box control. To copy the contents of an object array to a new one, you can use totalcross.sys.Vm.arrayCopy(). If you’re dealing specifically with string arrays, you may instead use totalcross.sys.Convert.cloneStringArray().
The list box also posts the ControlEvent.PRESSED when an item is clicked.
public void onEvent(Event event)
            {
             switch (event.type)
             {
              case ControlEvent.PRESSED:
              if (event.target == lb1)
              new MessageBox("TotalCross", "Item selected: " + lb1.getSelectedItem()).popup();
              break;
          }
      }
  
For more information, check the totalcross.ui.ListBox JavaDoc.

MultiEdit

MultiEdit is basically an edit with support for multiple lines, so their usage is pretty similar and, unless noted otherwise, the same methods listed for edit are available for MultiEdit. A static vertical scrollbar is added, but it is disabled/enabled as needed.
Here are some screenshots from a non-editable MultiEdit using the Android style from the old UIGadgets sample being scrolled (below it there is a multi-lined label):
figure companion_resources/images/multi_001.png figure companion_resources/images/multi_002.png
figure companion_resources/images/multi_003.png figure companion_resources/images/multi_004.png
An editable MultiEdit from the old UIControls sample (now inside the ui package from the TotalCrossAPI sample), also using Android style, can be seen below:
figure companion_resources/images/multi_005.png figure companion_resources/images/multi_006.png
figure companion_resources/images/multi_007.png
Here is an example showing a MultiEdit control being used:
public class MyProgram extends MainWindow
            {
             MultiEdit mEdit;
             ​
             public void initUI()
             {
              // the constructor method is called with the mask, the number of lines and the vertical interval in pixel between two lines
              add(mEdit,LEFT,TOP); // add/setRect must precede setText()
              mEdit.setText("What text you want"); // eventually
          }
      } 
  
Sample code:
public void initUI()
            {
             String s = "James Robert Baker (1946-1997) was an American author of sharply satirical, predominantly gay-themed transgressional fiction. A native Californian, his work is set almost entirely in Southern California. After graduating from UCLA, he began his career as a screenwriter, but became disillusioned and started writing novels instead. Though he garnered fame for his books Fuel-Injected Dreams and Boy Wonder, after the controversy surrounding publication of his novel, Tim And Pete, he faced increasing difficulty having his work published. According to his life partner, this was a contributing factor in his suicide. Baker’s work has achieved cult status in the years since his death, and two additional novels have been posthumously published. First-edition copies of his earlier works have become collector’s items. One of his novels was filmed (though it was not a financial success) and two others have been optioned for the movies, though they have not been produced.";
             ​
             MultiEdit mEdit;
             mEdit = new MultiEdit("",6,1);
             mEdit.drawDots = (false);
             mEdit.justify = true;
             mEdit.setEditable(false);
             mEdit.hasCursorWhenNotEditable = false;
             add(mEdit,LEFT,AFTER+2);
             mEdit.setText(s); //eventually
             mEdit.requestFocus();
         }
     
For more information, check the totalcross.ui.MultiEdit JavaDoc.

Grid

The grid control is used to display tabulated data, which is represented as a string matrix (each row is a string array). Optionally, you may add an extra column of checkboxes on the left side of the grid. Below are some examples of grid taken from TotalCross ShowCase

It is the most customizable control and it uses its own set of events defined in GridEvents (unlike the almost all the other controls that use only ControlEvents). That means you’ll be able to start using grids within a couple of minutes, but if you want to use all its features, it will take some time.

Although the TotalCross’ grid control usage is pretty simple and straightforward, it is the most customizable control and it uses its own set of events defined in GridEvents (unlike the almost all the other controls that use only ControlEvents). That means you’ll be able to start using grids within a couple of minutes, but it will take some time to learn to use all its features:

For more information, check the JavaDoc.

ToolTip

It allows the display of a tooltip when user keeps the pen in the control. On Windows and Linux desktop, the tooltip is also shown when the mouse stays over a control. The default popup delay (millisDelay) is 1000 ms and the amount of time it will be displayed (millisDisplay) is 2000 ms (a pen up also hides the control). The tooltip must always be added after the control is added and had its bounds set; otherwise, you must call the added method to initialize the tip’s bounds.
You can set the border color by changing the borderColor field (no border by default) and also the internal gap (the field insideGap). By default, it is -1 and no border is shown.
The static members distX and distY lets you set the default distance from the control for all tooltips. They must be set before the tooltip is created and are 0 by default.
The constructor receives the control which the tooptip refers to and the message that will be displayed. You can use the new line character \n like a label control. Example:
ToolTip t = new ToolTip(control, "Hi!\nIt’s Me"); 
                                
A ControlEvent.PRESSED event will be dispatched to the attached control right before the text is shown. You can then set the tip to a new value using setText(); setting to an empty string will disable the tooltip at that moment. Calling setControlRect() also changes the rectangle around which the tooltip will be displayed. By default, it’s used the absolute rectangle of the control passed in the constructor. The placement of the tooltip will be defined based on it, in a way that the control is not obscured.
ToolTip implements the PenListener interface.
Examples:
ToolTip.distX = 10; // 0 by default
                                    ToolTip.distY = 4; // 0 by default
                                    ToolTip.insideGap = 8; // 4 by default 
                                    Button b; 
                                    add(b = new Button("Hello Tooltip!"),CENTER,BOTTOM); 
                                    ​
                                    ToolTip t = new ToolTip(b, "Hi, this is a button");
                                    t.borderColor = 0x00FF00; // -1 (none) by default 
                                    t.millisDelay = 500; // 1000 by default t.millisDisplay = 4000; // 2000 by default
                                    t.setBackColor(Color.getRGB(250,0,0)); // same as control’s container by default 
                                
private void addToolTip(Control c, String text)
                                    {
                                     ToolTip t = new ToolTip(c,text);
                                     t.millisDelay = 500;
                                     t.millisDisplay = 5000;
                                     ​
                                     if (Settings.isColor)
                                     {
                                      t.borderColor = Color.BLACK;
                                      t.setBackColor(Color.getRGB(250,250,0));
                                  }
                              }
                              ​
                              public void initUI()
                              {
                                 add(btnChooseColor = new Button("Choose new background color"), LEFT, TOP+2);
                                 addToolTip(btnChooseColor, "Click this button to open a\nChoiceDialog that contains a\nColorList control from where\nyou can choose a back new color");
                             } 
                         
For more information, check the totalcross.ui.ToolTip JavaDoc.

 Some Advanced Controls

In this chapter, some advanced controls will be described in detail. They are organized in alphabetical order.

AlignedLabelsContainer

This class is a Container used to align all controls to the maximum width of a set of labels. You can define the label alignment. The controls that you add to this container are placed at the right of the labels.
Here’s a sample of how to use it:
String[] labels =
                            {
                             "Name",
                             "Born date",
                             "Telephone",
                             "Address",
                             "City",
                             "Country", 
                             ""
                         };
                         AlignedLabelsContainer c = new AlignedLabelsContainer(labels);
                         c.setBorderStyle(BORDER_LOWERED);
                         c.labelAlign = RIGHT;
                         c.foreColors = new int[]{Color.RED,Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,Color.BLACK,};
                         c.setInsets(2,2,2,2);
                         c.setFont(font.asBold()); // labels are bold
                         c.childrenFont = font; // but controls are normal
                         add(c,LEFT+2,TOP+2,FILL-2,PREFERRED+4);
                         for (int i =0; i < labels.length-2; i++)
                         c.add(new Edit(),LEFT+2,AFTER+(i==0?2:0));
                         c.add(new ComboBox(new String[]{"Brazil","France"}),LEFT+2,AFTER);
                         c.add(new Button("Insert data"),RIGHT,SAME);
                         c.add(new Button("Clear data"),RIGHT,AFTER,SAME,PREFERRED); 
                     
The code above generates a screen similar to the shown below taken from the old UIGadgets sample using Android style:
figure companion_resources/images/align_001.png
It is possible to do this alignment by hand. However, it is much easier using this control.
For more detais, take a look at totalcross.ui.AlignedLabelsContainer JavaDoc.

AnimatedButton

An animated button control. It extends Animation, the class described in the next section.
This control displays an animated button which can take S different states and each state is fade in or out in F frames. S and F represent the two first constructor arguments. The frames of this special animation have to be ordered to be supported by this class. The states are numbered from 0 to S-1 and the frames order is the following depending on the layout type value:
  • FADE_OUT_LAYOUT: S0F0,S0F1,S0F2,S1F0,S1F1,S1F2,S2F0,S2F1,S2F2
  • FADE_IN_LAYOUT: S0F2,S0F1,S0F0,S1F2,S1F1,S1F0,S2F2,S2F1,S2F0
  • FADE_OUT_IN_LAYOUT: S0F0,S0F1,S1F1,S1F0,S1F1,S2F1,S2F0,S2F1,S0F1
where S stands for state, F for frame and where S0F0, S1F0, and S2F0 are the full states and the others are transition frames.
Here is an example of how to use this class:
import totalcross.game.AnimatedButton;
                        import totalcross.io.IOException;
                        import totalcross.sys.Settings;
                        import totalcross.ui.*;
                        import totalcross.ui.image.*;
                        ​
                        public class Teste extends MainWindow
                        {
                         public Teste()
                         {
                          super("Teste", HORIZONTAL_GRADIENT);
                          setUIStyle(Settings.Android);
                      }
                      ​
                      AnimatedButton btn;
                      ​
                      public void initUI()
                      {
                          try
                          {
                           btn = new AnimatedButton(new Image("Ping_onOff.png"), 2,6,AnimatedButton.FADE_OUT_LAYOUT,-1,50);
                           add(btn, CENTER, CENTER);
                       }
                       catch (ImageException e) {}
                       catch (IOException e) {}
                   }
               }
           
where Ping_onOff.png is the following image:
figure companion_resources/images/Ping_onOff.png
which results in the following screenshots (the button starts an animation when it’s clicked on):
figure companion_resources/images/animatedbutton_001.png figure companion_resources/images/animatedbutton_002.png
figure companion_resources/images/animatedbutton_003.png figure companion_resources/images/animatedbutton_004.png
figure companion_resources/images/animatedbutton_005.png figure companion_resources/images/animatedbutton_006.png
figure companion_resources/images/animatedbutton_007.png figure companion_resources/images/animatedbutton_008.png
figure companion_resources/images/animatedbutton_009.png figure companion_resources/images/animatedbutton_010.png
figure companion_resources/images/animatedbutton_011.png figure companion_resources/images/animatedbutton_012.png
For more detais, take a look at totalcross.game.AnimatedButton JavaDoc.

Animation

This control displays an animation that can be loaded from indexed PNG files (one frame per image), a multi-framed PNG (this kind of PNG file contains a list of images having all the same size and that lay side by side), or a GIF. Some examples taken from the game Scape and GifAnimatedTest are shown below, where the first one uses multi-framed PNGs and the second one uses GIFs (the PNG images are below the sample windows which use them):
figure companion_resources/images/animation_001.png figure companion_resources/images/animation_002.png
figure companion_resources/images/hockey.png figure companion_resources/images/ball.png
figure companion_resources/images/animation_003.png figure companion_resources/images/animation_004.png
For more detais, take a look at totalcross.game.Animation JavaDoc.

ArrowButton

A class used to display a Button with an arrow inside. The following code shows the window below it:
import totalcross.sys.Settings;
            import totalcross.ui.*;
            import totalcross.ui.gfx.*;
            ​
            public class Teste extends MainWindow
            {
             public Teste()
             {
              super("Teste", HORIZONTAL_GRADIENT);
              setUIStyle(Settings.Android);
          }
          ​
          public void initUI()
          {
              ArrowButton b1 = new ArrowButton(Graphics.ARROW_UP, 10, Color.BLACK);
              add(b1, LEFT, TOP);
              ArrowButton b2 = new ArrowButton(Graphics.ARROW_DOWN, 20, Color.BLUE);
              add(b2, AFTER, SAME);
              ArrowButton b3 = new ArrowButton(Graphics.ARROW_LEFT, 30, Color.CYAN);
              add(b3, LEFT, AFTER);
              ArrowButton b4 = new ArrowButton(Graphics.ARROW_RIGHT, 40, Color.GREEN);
              add(b4, AFTER, SAME);
          }
      }
  
figure companion_resources/images/arrowbutton_001.png
In this class, setArrowSize(int kk) Changes the arrow size of the button. Note that the button size won’t be changed. Some examples using b4 of the above picture:
b4.setArrowSize(20); b4.setArrowSize(80);
figure companion_resources/images/arrowbutton_002.png figure companion_resources/images/arrowbutton_003.png
toString() shows a string representation of the object and its direction. For example, the code below
Vm.debug(b1.toString());
            Vm.debug(b2.toString());
            Vm.debug(b3.toString());
            Vm.debug(b4.toString());
        
prints the following on the console:
totalcross.ui.ArrowButton@131f71a, dir: 1 
            totalcross.ui.ArrowButton@15601ea, dir: 2 
            totalcross.ui.ArrowButton@197d257, dir: 3 
            totalcross.ui.ArrowButton@7259da, dir: 4
        
For more detais, take a look at totalcross.game.ArrowButton JavaDoc.

Bar

Bar is a class that provides a title area and a button area (at right). The title and the button are optional, although it doesn’t make sense to have a bar without title and buttons. You can add or remove buttons, and change the title text; the title text can have an icon at left.
When a button is pressed, a ControlEvent.PRESSED is sent to the caller, and the button index can be retrieved using the getSelectedIndex() method. By default, the background is shaded (BACKGROUND_SHADED). You can change it to plain using
backgroundStyle = BACKGROUND_SOLID;
        
Here’s an example of how to use it:
Font f = Font.getFont(true,Font.NORMAL_SIZE+2);
            Bar h1 = new Bar("fakeboot");
            h1.canSelectTitle = true;
            h1.setFont(f);
            h1.setBackForeColors(0x0A246A,Color.WHITE);
            h1.addButton(new Image("ic_dialog_alert.png"));
            h1.addButton(new Image("ic_dialog_info.png"));
            add(h1, LEFT,0,FILL,PREFERRED); // use 0 instead of TOP to overwrite the default menu area 
        
which results in the following images using Android style, where the bottom images show the title and one of the buttons being pressed:
figure companion_resources/images/bar_001.png
figure companion_resources/images/bar_002.png figure companion_resources/images/bar_003.png
Note that the top and bottom components of the the old UIControls sample (now inside the ui package from the TotalCrossAPI sample) are bars.
You can also add a spinner to the bar and manipulate it using the following methods:
  • createSpinner(int color) Creates a spinner with the given color. The spinner will be placed at the right of the title (only works if there’s a title). It must be created before the bar is added to a container.
  • startSpinner() Shows and starts the spinner (if one has been assigned to the spinner field). If there is no spinner, a NullPointerException will be thrown.
    Changing the code of the example given above after line 7 results in:
    h1.createSpinner(Color.WHITE);
                    add(h1, LEFT,0,FILL,PREFERRED); // use 0 instead of TOP to overwrite the default menu area
                    h1.startSpinner();
                
figure companion_resources/images/bar_004.png
  • stopSpinner() Stops and hides the spinner (if one has been assigned to the spinner field). If there is no spinner, a NullPointerException will be thrown.
For more detais, take a look at totalcross.ui.Bar JavaDoc.

ButtonMenu

This class adds a multi-button menu that can be scrolled horizontally (single-row) or vertically (multiple-rows), using a scroll bar or flicking. The buttons can have almost all properties present in the Button class, like (the ButtonMenu fields listed below similar to the ones in the class Button are ommited from the fields description at the end of this section):
  • borderType (Button.setBorder())
  • cornerRadius3DG (Button.cornerRadius3DG)
  • borderWidth3DG (Button.borderWidth3DG)
  • borderColor3DG (Button.borderColor3DG)
  • topColor3DG (topColor3DG)
  • bottomColor3DG (bottomColor3DG)
  • pressedColor (Button.setPressedColor())
There are also other properties that can be set, like:
  • textGap
  • buttonVertGap
  • buttonHorizGap
  • imageSize
  • borderGap
The sizes above are not in pixels, but in percentage of the font’s height. So, a value of 25 means 25% of the font’s height, or 1/4; 150 means 150% of the font’s height, or 1.5x; and so on. This enabled the gaps be constant in physical inches no matter the screen DPI or resolution.
The UIContols program has good samples on how to use this class. Some images are shown below:
figure companion_resources/images/buttonmenu_001.png
figure companion_resources/images/buttonmenu_002.png figure companion_resources/images/buttonmenu_003.png
figure companion_resources/images/buttonmenu_004.png figure companion_resources/images/buttonmenu_005.png
For more detais, take a look at totalcross.ui.ButtonMenu JavaDoc.

ComboBoxEditable

This control is a ComboBox and is usually used as an edit that holds old typed values. When the user types a word, it is automatically selected in the combo box. Here’s a sample of how to use it similar to the one used to be found in the old UIGadgets samples:
String[] items = 
            {
             "Ana",
             "Barbara",
             "Raul",
             "Marcelo",
             "Eduardo",
             "Denise",
             "Michelle",
             "Guilherme",
             "Vera",
             "Dulce",
             "Leonardo",
             "Andre",
             "Gustavo",
             "Anne",
             "Renato",
             "Zelia",
             "Helio"
         };    
         ComboBoxEditable cbe = new ComboBoxEditable(items);
         cbe.qsort();
         add(cbe, LEFT,BOTTOM-100);  
     
The next images show the result of this sample and some screenshots from the old sample:
figure companion_resources/images/comboeditable_001.png figure companion_resources/images/comboeditable_002.png
figure companion_resources/images/comboeditable_003.png figure companion_resources/images/comboeditable_004.png
figure companion_resources/images/comboeditable_005.png
For more detais, take a look at totalcross.ui.ComboBoxEditable JavaDoc.

ColorList

Implements a ListBox where colors can be choosen from. The only functional methods are setColors(), getSelectedItem() and getSelectedColor(). Next an example of how to use this class as a combo box color chooser:
add(foreCombo = new ComboBox(new ColorList()), CENTER, BOTTOM); 
        
which results in the following windows:
figure companion_resources/images/colorlist_001.png figure companion_resources/images/colorlist_002.png
figure companion_resources/images/colorlist_003.png figure companion_resources/images/colorlist_004.png
For more detais, take a look at totalcross.ui.ColorList JavaDoc.

Document

Represents an HTML Document. To change the font size, you must change Style.
defaultFontSize
. To change the default colors, change UIColors.htmlXXX fields, and don’t forget to call htmlContainer.setBackForeColors() with these colors.
To see it being used, see the sample HtmlBrowser. Some screen shots of it are in the section HtmlContainer↓.
For more detais, take a look at totalcross.ui.html.Document JavaDoc.

FlowContainer

This class is a container that will place controls one after another and, once the width has been reached, it wraps to the next line. All controls must be added before calling setRect() or add(). When calling setRect() or add() for this control, the height must be PREFERRED (with adjustments, if needed). Also, if initUI() is overriden, be sure to call super.initUI().
Code example:
Settings.uiAdjustmentsBasedOnFontHeight = true;
            Label l = new Label("Do you agree that TotalCross is a great development platform?");
            l.autoSplit = true;
            add(l, LEFT,AFTER,FILL,PREFERRED);
            ​
            FlowContainer fc = new FlowContainer(50,25);
            fc.add(new Radio("Probably Yes"));
            fc.add(new Radio("Probably No"));
            fc.add(new Radio("Maybe"));
            fc.add(new Radio("I don’t know"));
            add(fc, LEFT,AFTER,FILL,PREFERRED); 
        
which results in:
figure companion_resources/images/flow_001.png
For more detais, take a look at totalcross.ui.FlowContainer JavaDoc.

HtmlContainer

HtmlContainer renders an HTML Page.
Note that the form controls back and fore colors are defined by UIColors.
htmlContainerControlsFore
and UIColors.htmlContainerControlsBack.
When a link is clicked, a PRESSED event is thrown, with this HtmlContainer as target. The link can then be retrieved with the pressedLink property.
Some images taken from the old sample HtmlBrowser, which uses this control, are shown here, where the application interface style was changed to Android:
figure companion_resources/images/html_001.png figure companion_resources/images/html_002.png
figure companion_resources/images/html_003.png figure companion_resources/images/html_004.png
figure companion_resources/images/html_005.png figure companion_resources/images/html_006.png
figure companion_resources/images/html_007.png figure companion_resources/images/html_008.png
For more detais, take a look at totalcross.ui.html.HtmlContainer JavaDoc.

ImageControl

A control that can show an image bigger than its area and that can be dragged using a pen to show the hidden parts. Note that, by default, events (and dragging) are disabled. You must call setEventsEnabled() to allow dragging.
This is used in the Litebase sample PhotoDB, where it is possible to drag the picture to show other parts of it.
For more detais, take a look at totalcross.ui.ImageControl JavaDoc.

ImageList

Implements a ListBox where the items are images. If you don’t add at least one image before calling add()/setRect(), you must compute the preferred size yourself.
Next an example of how to use this class as a combo box color chooser:
import totalcross.io.IOException;
            import totalcross.sys.Settings;
            import totalcross.ui.*;
            import totalcross.ui.image.*;
            ​
            public class Teste extends MainWindow
            {
             public Teste()
             {
              super("Teste", HORIZONTAL_GRADIENT);
              setUIStyle(Settings.Android);
          }
          public void initUI()
          {
              ImageList list = new ImageList();
              try
              {
               list.add(new Image("black.png"));
               list.add(new Image("blue.png"));
               list.add(new Image("green.png"));
               list.add(new Image("red.png"));
               list.add(new Image("white.png"));
           }
           catch (ImageException e) {}
           catch (IOException e) {}
           add(new ComboBox(list), CENTER, BOTTOM);
       }
   }
Using 32x32 images, the result of the above code is the following:
figure companion_resources/images/imagelist_002.png figure companion_resources/images/imagelist_001.png
For more detais, take a look at totalcross.ui.ImageList JavaDoc.

ListContainer

ListContainer is a ListBox where each item is a Container.
The correct way to create a ListContainer item is by subclassing a Container and adding the controls in the initUI() method. Adding directly using getContainer().add() will not work.

The List Container at Totalcross 5.0.0 snapshot:


Below is an example of how to use it, taken from the old UIGadgets sample using the Android user interface style:
class LCItem extends ScrollContainer
            {
             Label lDate,lPrice,lDesc;
             Check chPaid;
             ​
             public LCItem()
             {
              super(false); // VERY IMPORTANT (a RuntimeException will be thrown if this is not used because it can’t have a scroll bar).       
          }

          public void initUI()
          {
              add(chPaid = new Check("Paid"),LEFT,TOP);
              add(lDate = new Label("99/99/9999"),RIGHT,TOP);
              add(new Label("US$"),LEFT,AFTER);
              add(lPrice = new Label("999.999.99"),AFTER,SAME);
              add(lDesc = new Label("",RIGHT),AFTER+10,SAME);
              lDesc.setText("description");
          }
      }
      ​
      private void testListContainer()
      {
         ListContainer lc;
         add(lc = new ListContainer(),LEFT,TOP,FILL,FILL);
         for (int i =0; i < 10; i++)
         lc.addContainer(new LCItem());
     } 
 
The resulting window from it looks like the screenshots below:
figure companion_resources/images/listcontainer_001.png figure companion_resources/images/listcontainer_002.png
From the old UIControls sample (now inside the ui package from the TotalCrossAPI sample), the following screenshots were taken:
figure companion_resources/images/listcontainer_003.png figure companion_resources/images/listcontainer_004.png

MenuBar

For more detais, take a look at totalcross.ui.ListContainer JavaDoc.
Constructs a menu with the given items. A menu can be opened by the user in a couple of ways:
  • By clicking on the menu button on the devices.
  • By clicking on the title of a window.
  • By holding during 1 second the middle button of the 5-way navigation buttons.
The menu supports disabled and checked items. The menu can be closed by a click on a valid item or clicking outside of its bounds. A PRESSED event will be thrown when the menu is closed and a menu item was selected. To discover which item was selected, see the method getSelectedIndex(), which returns -1 if none, or the matrix index otherwise.
Note that the separator dotted line doesn’t generate events and can’t be selected.
After changing the isChecked and isEnabled states, there’s no need to call repaint(), because they will show up only the next time the menu bar opens.
Here is an example of a menu bar taken from the old UIGadgets sample:
MenuItem col0[] =
            {
             new MenuItem("File"),
             new MenuItem("Minimize"),
             new MenuItem("Exit"),
             new MenuItem(),
             miShowKeys = new MenuItem("Show key codes", false)
         };       
         String p = Settings.platform;
         col0[1].isEnabled = p.equals(Settings.JAVA) || p.equals(Settings.ANDROID) || Settings.isWindowsDevice() || p.equals(Settings.WIN32);
         ​
         MenuItem col1[] =
         {
             new MenuItem("UIStyle"),
             new MenuItem("Flat"),
             new MenuItem("Vista"),
             new MenuItem("Android"),
             new MenuItem(),
             miPenless = new MenuItem("Penless device",false),
             miGeoFocus= new MenuItem("Geographical focus",false),
             new MenuItem(),
             miUnmovableSIP = new MenuItem("Unmovable SIP",false)
         };
         ​
         MenuItem col2[] =
         {
             new MenuItem("Tests1"),
             new MenuItem("Standard controls"),
             new MenuItem("TabbedContainer with images"),
             new MenuItem("Masked Edit"),
             new MenuItem("Image and text buttons"),
             new MenuItem("Scaled Image button"),
             new MenuItem("Justified MultiEdit and Label")
         };
         ​
         MenuItem col3[] =
         {
             new MenuItem("Tests2"),
             new MenuItem("Scroll Container"),
             new MenuItem("File Chooser with Tree"),
             new MenuItem("SpinList ToolTip ProgressBar"),
             new MenuItem("Drag scroll"),
             new MenuItem("AlignedLabelsContainer"),
             new MenuItem("ListContainer"),
         };
         ​
         setMenuBar(mbar = new MenuBar(new MenuItem[][]{col0,col1,col2,col3}));
     
The result of this sample is shown in the images below taken from the old UIGadgets sample using Android user interface style:
figure companion_resources/images/menubar_001.png figure companion_resources/images/menubar_002.png
figure companion_resources/images/menubar_003.png figure companion_resources/images/menubar_004.png
For more detais, take a look at totalcross.ui.MenuBar JavaDoc.

Side Menu

The SideMenu component is a navigation drawer that slides on the side of the current view. By default, slide from the left, but the side can be replaced. The sideMenu is customized through containers and specifications that allow you to set the SideMenu object or through the SideMenuContainer class.

Project Considerations

The sideMenu, as an important part of the user interface, have their own standards. Therefore it is recommended to review the Material Design for more information and to enjoy the component better. To learn how to design notifications and their interactions, read what MaterialDesing talks about Menus.

Creating SideMenu

First, you create the SideMenuContainer object and inside the initUI() you instantiate the objects corresponding to the items, through the SideMenuContainer.Item and there you pass the characteristics you want, such as caption, icon, presenter.

After that, you instantiate your SideMenuContainer object and point to the SideMenuContainer.item that you created earlier.

And then just customize the header of your SideMenu through topMenu.header.

And finally just pass the other information you want on your sideMenuContainer object, such as font color, bar size and so on.

Content Needed to Create a SideMenu

  • sideMenuContainer
  • sideMenuContainer.Item
    • Capition
    • Image or IconType
    • Presenter
  • TopMenu.Header
  • Icon _Menu

Optional SideMenu Settings and Content

Inside the sideMenuContainer.Item you can still have:

  • Caption
  • Image or IconType (advise using MaterialIcon)
  • Color
  • Boolean showTitle
  • Presenter

Inside the sideMenuContainer.Sub which is an item with subitens, you can have:

  • Caption or String
  • Control

And you can even specify directly in the sideMenuContainer.topMenu:

  • .drawSeparators = boolean - To place or not the lines separating the items
  • .itemHeightFactor = int - To say the item's size.

Creating a Simple SideMenu


    public void initUI(){
    //Creates items with caption, icon, icon color and control
    SideMenuContainer.Item home = new SideMenuContainer.Item("Home", MaterialIcons._HOME, 0x4A90E2, ()-> {return new Home();});
    SideMenuContainer.Item sample = new SideMenuContainer.Item("Home", MaterialIcons._THUMB_UP, 0x4A90E2, ()-> {return new Sample();});

    // Creates the sub menu, passing the caption and the controls that must be contain
    SideMenuContainer.Sub submenu = new SideMenuContainer.Sub("Components", sample);

    //Places the itens inside the menu
    SideMenuContainer sideMenu = new SideMenuContainer(null, home, submenu);

    //Specifies the components that should contain in the menu header especifica os componentes que deve conter no header do menu       
    sideMenu.topMenu.header = new Container(){
    public void initUI(){
    setBackColor(0xaa443b);

    Label title = new Label("SideMenu", CENTER, Color.WHITE, false);
    title.setFont(Font.getFont("Lato Bold", false, this.getFont().size+5));
    title.setForeColor(Color.WHITE);
    add(title, LEFT+45, BOTTOM-45, PARENTSIZE+40, DP+56);
}
};
//Set the additional characteristics in the menu, such as bar size, background color and others.
sideMenu.setBarFont(Font.getFont(Font.getDefaultFontSize()+2));
sideMenu.setBackColor(0x4A90E2);
sideMenu.setForeColor(Color.WHITE);
sideMenu.setItemForeColor(Color.BLACK);
sideMenu.topMenu.drawSeparators = false;
sideMenu.topMenu.itemHeightFactor = 3;

Icon icon = new Icon(MaterialIcons._MENU);
icon.setBackColor(Color.WHITE);
add(icon, CENTER, TOP);
add(sideMenu, LEFT, TOP, PARENTSIZE, PARENTSIZE);
}

Very simple! To see the complete example, just click here.

MenuBarDropDown

Constructs a MenuBarDropDown with the given items. This class is used in conjunction with the MenuBar. However, you can also use it to create a stand alone "right click" menu. The menu items must fit on the screen. No clipping is applied. Also, the font and colors can be changed if desired.
Here is an example of how to build a stand alone MenuBarDropDown:
import totalcross.sys.Settings;
            import totalcross.ui.*;
            ​
            public class Teste extends MainWindow
            {
             public Teste()
             {
              super("Teste", HORIZONTAL_GRADIENT);
              setUIStyle(Settings.Android);
          }

          public void initUI()
          {
              MenuItem col1[] = // note that the first string is always skipped (it would be the MenuItem title in the MenuBar)
              {
               new MenuItem("Record"),
               new MenuItem("NewEvent"),
               new MenuItem("Delete Note..."),
               new MenuItem("Purge..."),
               new MenuItem(), // create a dotted line
               new MenuItem("Beam Event")
           };
           MenuBarDropDown pop = new MenuBarDropDown(10,10,col1);
           pop.popupNonBlocking();
       }
   }
which results in the following window:
figure companion_resources/images/menubardropdown_001.png
For more detais, take a look at totalcross.ui.MenuBarDropDown JavaDoc.

MultiListBox

MultiListBox is a ListBox that allows more than one item to be selected. The maximum number of selections can be defined using setMaxSelections(). Be sure to save a reference to the MultiListBox so you can call the specific methods of this class.
To create a ComboBox with a MultiListBox, use:
MultiListBox mlb;
            new ComboBox(mlb = new MultiListBox()) 
        
getSelectedIndex() returns just the last selected index; to retrieve all indexes, use
getSelectedIndexes().
In penless devices, there will be a cursor which will be used to highlight an item; to select or unselect it, you must press the left key. MultiListBox requires the useFullWidthOnSelection on penless devices.
The following screenshots from the old UIGadgets sample using Android user interface style shows the MultiListBox behavior:
figure companion_resources/images/multilist_001.png figure companion_resources/images/multilist_002.png
figure companion_resources/images/multilist_003.png figure companion_resources/images/multilist_004.png
For more detais, take a look at totalcross.ui.MultiListBox JavaDoc.

PagePosition

PagePosition implements the empty and filled balls that indicates the current page in a set of pages, very common on Android and iOS. PagePosition and Flick use it. It has three properties:
  • visibleCount: the number of visible balls.
  • count: the number of balls that will be displayed. It can be less, equal, or greater than the visible count.
  • position: the current position of the filled ball.
PagePosition is shown in the image below from the old UIControls sample (now inside the ui package from the TotalCrossAPI sample) above the mouse cursor, where it is inside a ButtonMenu:
figure companion_resources/images/pageposition_001.png
For more detais, take a look at totalcross.ui.PagePosition JavaDoc.

Ruler

Ruler is a horizontal or vertical ruler. Here’s an example:
Ruler r = new Ruler();
            r.invert = true;
            add(r, LEFT,AFTER+2);  
        
which results in the following using Android style:
figure companion_resources/images/ruler_001.png
The old UIGadgets sample also used a default ruler shown near the mouse arrow:
figure companion_resources/images/ruler_002.png
For more detais, take a look at totalcross.ui.Ruler JavaDoc.

PopupMenu

Creates a popup menu with a single line list and some radio buttons at right, like the Android combo box styles. The PRESSED event is sent when an item is selected. The colors must be set before the control’s bounds are defined using setRect() or add().
This is a sample of how to use it:
String[] items =
            {
             "Always",
             "Never",
             "Only in Silent mode",
             "Only when not in Silent mode",
             "None of the answers above"
         }; 
         PopupMenu pm = new PopupMenu("Vibrate",items);
         pm.popup(); 
     
which results in a window similar to the one below:
figure companion_resources/images/popmenu_001.png figure companion_resources/images/popmenu_002.png
For more detais, take a look at totalcross.ui.PopupMenu JavaDoc.

ProgressBar

A basic progress bar, with the bar and a text. The text is comprised of a prefix and a suffix.
You can create a horizontal endless progress bar, always going from left to right, by setting the given parameters:
  • Call setEndless().
  • max-min: used to compute the width of the bar.
  • prefix and suffix: displayed, but the current value is not displayed.
  • setValue(n): n used to increment the current value, not to set the value to n.
Then set a timer to update the value.
Here is some progress bar samples taken from the old UIGadgets and UIControls samples (now inside the ui package from the TotalCrossAPI sample), using Android user interface style:
figure companion_resources/images/progressbar_006.png figure companion_resources/images/progressbar_002.png
For more detais, take a look at totalcross.ui.ProgressBar JavaDoc.

PushButtonGroup

Group or matrix of push buttons in a single control. It is one of the most versatiles controls of TotalCross. The width of each button is calculated based on its caption size plus insideGap, if you use PREFERRED as the width; otherwise, it uses the size you specified (e. g.: FILL, FIT, etc). The height is calculated based on the font’s size or on the height you specified.
Here is an example of constructor:
new PushButtonGroup(new String[]{"Button1", "Button2", "Button3"},  false, -1, -1, 4, 0, false, PushButtonGroup.NORMAL); 
        
which results in this window when the control is added to its center using Android user interface style:
figure companion_resources/images/pushbutton_001.png figure companion_resources/images/pushbutton_002.png
figure companion_resources/images/pushbutton_003.png figure companion_resources/images/pushbutton_004.png
Also using Android user interface style, the screenshots below from the old UIGadgets sample also show this control being used:
figure companion_resources/images/pushbutton_005.png figure companion_resources/images/pushbutton_006.png
This class has two very important fields called colspan and rowspan, which spans a cell across multiple columns and rows. These cells that will be overriden must be null and the parameter allSameWidth passed in the constructor must be true. This sample:
String []numerics = {"1", "2", "3", "4", "5", "6", "7", "clear", null, "0", null, null};
            PushButtonGroup pbg = new PushButtonGroup(numerics, false, -1, 4, 0, 4, true, PushButtonGroup.BUTTON);
            pbg.colspan[7] = 2;
            pbg.rowspan[7] = 2;
            add(pbg, LEFT+50,AFTER+50,FILL-50,FILL-50); 
        
will show this:
figure companion_resources/images/pushbutton_007.png
For more detais, take a look at totalcross.ui.PushButtonGroup JavaDoc.

ScrollBar

The scroll bar orientation can be horizontal or vertical. It implements auto scroll when pressing and holding a button or the gap area of the scroll bar. Here is an example of how to use it.
import totalcross.sys.Settings;
            import totalcross.ui.*;
            import totalcross.ui.event.*;
            public class Teste extends MainWindow
            {
             ScrollBar sb1, sb2, sb3, sb4;
             ​
             public Teste()
             {
              super("Teste", HORIZONTAL_GRADIENT);
              setUIStyle(Settings.Android);
          }
          ​
          public void initUI()
          {
              add(sb1 = new ScrollBar(ScrollBar.VERTICAL), RIGHT, CENTER, PREFERRED, Settings.screenHeight/2);
              add(sb2 = new ScrollBar(ScrollBar.VERTICAL), BEFORE, SAME, PREFERRED, SAME);
              sb2.setLiveScrolling(true);
              add(sb3 = new ScrollBar(ScrollBar.HORIZONTAL), LEFT,CENTER, Settings.screenWidth/2, PREFERRED);
              add(sb4 = new ScrollBar(ScrollBar.HORIZONTAL), SAME, AFTER, SAME, PREFERRED);
          }
          ​
          public void onEvent(Event event)
          {
              if (event.type == ControlEvent.PRESSED && event.target == sb2)
              {
               int value = sb2.getValue();
               sb1.setValue(value);
               sb3.setValue(value);
               sb4.setValue(value);
           }
       }
   }
which results in the following images:
figure companion_resources/images/scrollbar_001.png figure companion_resources/images/scrollbar_002.png
figure companion_resources/images/scrollbar_003.png figure companion_resources/images/scrollbar_004.png
For more detais, take a look at totalcross.ui.ScrollBar JavaDoc.

ScrollContainer

This is a container with a horizontal only, vertical only, both, or no scroll bars, depending on the control positions. The default unit scroll is an edit’s height (for the vertical scrollbar), and the width of an @ (for the horizontal scrollbar).
Caution: you must not use RIGHT, BOTTOM, CENTER, and FILL when setting the control bounds, unless you disable the corresponding scroll bar! The only exception to this is to use FILL on the control’s height, which is allowed.
Here is an example showing how it can be used:
import totalcross.sys.Settings; 
            import totalcross.ui.*;
            ​
            public class Teste extends MainWindow 
            {    
             public Teste()
             {
              super("Teste", HORIZONTAL_GRADIENT);
              setUIStyle(Settings.Android);
          }
          ​
          ScrollContainer sc;

          public void initUI()
          {
              ScrollContainer sc;
              add(sc = new ScrollContainer());
              sc.setBorderStyle(BORDER_SIMPLE);
              sc.setRect(LEFT+10,TOP+10,FILL-20,FILL-20);
              int xx = new Label("Name99").getPreferredWidth()+2; // edit’s alignment
              for (int i =0; i < 100; i++)
              {
               sc.add(new Label("Name"+i),LEFT,AFTER);
               sc.add(new Edit("@@@@@@@@@@@@@@@@@@@@"),xx,SAME);
               if (i % 3 == 0)
               sc.add(new Button("Go"), AFTER+2,SAME,PREFERRED,SAME);
           }
       }
   }
which results in the following screenshots:
figure companion_resources/images/scrollcontainer_001.png figure companion_resources/images/scrollcontainer_002.png
figure companion_resources/images/scrollcontainer_003.png figure companion_resources/images/scrollcontainer_004.png
UIControl uses this control in almost all windows so that its components can be scrolled. The old UIGadgets sample also uses it in one of its tests. Using Android user interface style, the following screenshot can be seen:
figure companion_resources/images/scrollcontainer_005.png
For more detais, take a look at totalcross.ui.ScrollContainer JavaDoc.

ScrollPosition

ScrollPosition implements the auto-hide scroll bar that exists in finger-touched devices. This special scroll bar is just a small position indicator that appears when the area is dragged.
ScrollPosition
does not take an area of the control, since it appears and disappears automatically. All Scrollable controls change their ScrollBar by ScrollPosition when Settings.fingerTouch = true. If the back color and the bar color are the same, the bar is not drawn; this is how the ButtonMenu class hides this control.
Some images of it can be found in the old UIControls sample (now inside the ui package from the TotalCrossAPI sample) when scrolling its main window:
figure companion_resources/images/scrollposition_001.png figure companion_resources/images/scrollposition_002.png
For more detais, take a look at totalcross.ui.ScrollPosition JavaDoc.

Slider

Slider is a simple slider. You can set some properties of the slider, like drawTicks,
invertDirection
and drawFilledArea. You can change the thumb size by setting the minDragBarSize public field and then call setValues(), setMaximum(), or setMinimum() method (the value must always be ODD!). The slider is the component pointed by the mouse arrow in the old UIGadgets sample using the Android style below:
figure companion_resources/images/slider_001.png
For more detais, take a look at totalcross.ui.Slider JavaDoc.

Spacer

Control used to add a space between controls. It shows nothing on screen.
Here’s a sample of how to use it:
Spacer s = new Spacer("  ");
            Button btnClear = new Button("Clear");
            Button btnOK = new Button("OK");
            add(s, CENTER,AFTER+2);
            add(btnClear, AFTER,SAME, s);
            add(btnOK, BEFORE, SAME, SAME, SAME, s); 
        
which results in the following using Android style, which places two buttons centered on screen, like this:
figure companion_resources/images/spacer_001.png
The spacer is also used to separate the spinners in the Spinner samples of old UIControls sample (now inside the ui package from the TotalCrossAPI sample) and the back and next buttons from the old Litebase sample PhotoDB using the old Windows CE style (now inside the sample Address Book and using Android style):
figure companion_resources/images/spacer_002.png figure companion_resources/images/spacer_003.png
For more detais, take a look at totalcross.ui.Spacer JavaDoc.

SpinList

Creates a control with two arrows, so that you can scroll values and show the current one. It supports auto-scroll (by clicking and holding) and can also dynamically compute the items based on ranges. The spin list can be horizontal or vertical. You can use something like:
SpinList sl = new SpinList(..., !Settings.fingerTouch); 
        
This way, in finger-touch devices, it will use the horizontal appearance, which is easier to deal with on such devices.
The screenshots below from the old UIGadgets sample using Android user interface style shows the days being increased and decreased when pressing the increase or decrease arrow, respectively:
figure companion_resources/images/spinlist_001.png figure companion_resources/images/spinlist_002.png
figure companion_resources/images/spinlist_003.png figure companion_resources/images/spinlist_004.png
For more detais, take a look at totalcross.ui.SpinList JavaDoc.

Spinner

Spinner is a control that shows an image indicating that something is running in the background. It has two styles: IPHONE and ANDROID. It’s used in the ProgressBox and can be used in the Bar. To start the spin call the start() method, and to stop it call the stop() method. An image of it has already been shown in section Ruler↑.
For more detais, take a look at totalcross.ui.Spinner JavaDoc.

TabbedContainer

TabbedContainer is a bar of text or image tabs. It is assumed that all images will have the same height, but they may have different widths. A scroll is automatically added when the total width of the titles is bigger than the control’s width. The containers are created automatically and switched when the user presses the corresponding tab.
When the user interface has Android style, the tabs do not look good if the background is the same of the parent’s. In this case, we force the background to be slighly darker. There are a few fields that you can use to change the color, like activeTabBackColor,
useOnTabTheContainerColor
, and pressedColor.
Important: with Settings.fingerTouch = true, you CANNOT call setRect() in your container. Otherwise, the flick and drag will not work and your container will be positioned incorrectly.
Below are some screenshots taken from the old UIGadgets (using Android user interface style) and UIControls (now inside the ui package from the TotalCrossAPI sample) samples:
figure companion_resources/images/tabbedcontainer_001.png figure companion_resources/images/tabbedcontainer_002.png
figure companion_resources/images/tabbedcontainer_003.png
figure companion_resources/images/tabbedcontainer_004.png figure companion_resources/images/tabbedcontainer_005.png
figure companion_resources/images/tabbedcontainer_006.png
For more detais, take a look at totalcross.ui.TabbedContainer JavaDoc.

Tree

This class is a simple implementation of a tree widget. Since it’s natural to render the tree in rows, this class borrows most of the code from ListBox. Features:
  • Similar to Microsoft Windows Explorer tree.
  • Horizontal and vertical scrolling.
  • Allows setting of folder and leaf icons.
  • Expands and collapses of folder.
  • allowsChildren flag to determine if the node is a leaf or a folder.
  • Delete, insert, and modify (user object or identifier) of a node.
  • Clicking on a leaf node will swap to the leaf icon (like hyperlink).
  • Allows the creation of a tree to show or hide the root node.
You should use the TreeModel class to modify the tree after and the class Node to add nodes to the tree. Here’s a sample:
TreeModel tmodel = new TreeModel();
            Tree tree = new Tree(tmodel);
            add(tree,LEFT,TOP,FILL,FILL);
            Node root = new Node("Tree");
            tmodel.setRoot(root);
            Node n;
            root.add(n = new Node("Branch1"));
            n.add(new Node("SubBranch1"));
            n.add(new Node("SubBranch2")); 
        
which results in the following window (using Android style):
figure companion_resources/images/tree_001.png figure companion_resources/images/tree_002.png
The old UIGadgets sample also has a sample called FileChooserTest which uses Tree. Using Android style, it looks like this:
figure companion_resources/images/tree_003.png
For more detais, take a look at totalcross.ui.tree classes JavaDocs.

Whiteboard

This is a whiteboard that can be used to draw something. It uses a special event flag in order to improve the accuracy.
The sample Painter uses it. The pictures below show its whiteboard empty and drawn, respectively, where the application interface style was changed to Android:
figure companion_resources/images/white_001.png figure companion_resources/images/white_002.png
For more detais, take a look at totalcross.ui.WhiteBoard JavaDoc.

MultiButton

MultiButton is a control that displays a single line button with a set of titles. It can be used to replace a check (with on/off) or a radio (with their options). Below there is a sample taken from old UIControls sample (now inside the ui package from the TotalCrossAPI sample):
figure companion_resources/images/multi_button_001.png figure companion_resources/images/multi_button_002.png
For more detais, take a look at totalcross.ui.MultiButton JavaDoc.

 Charts

Here a list of chart classes supported by TotalCross. They are located in the package totalcross.ui. chart. Read their JavaDocs for more information.

Chart

The base class of all Chart classes.

ColumnChart

This is a a vertical column chart. Below are shown some screenshots taken from the old sample CharTest (now inside the ui package from the TotalCrossAPI sample):
figure companion_resources/images/chart_001.png figure companion_resources/images/chart_002.png
figure companion_resources/images/chart_003.png figure companion_resources/images/chart_004.png
figure companion_resources/images/chart_005.png figure companion_resources/images/chart_016.png

PointLineChart

Abstract class used by points and line charts, extended by LineChart and XYChart.

LineChart

This class represents a line chart. Below are shown some screenshots taken from the old CharTest sample (now inside the ui package from the TotalCrossAPI sample):
figure companion_resources/images/chart_006.png figure companion_resources/images/chart_007.png
figure companion_resources/images/chart_008.png figure companion_resources/images/chart_009.png
figure companion_resources/images/chart_010.png

PieChart

A simple pie chart. Below are shown some screenshots taken from the old CharTest sample (now inside the ui package from the TotalCrossAPI sample):
figure companion_resources/images/chart_011.png figure companion_resources/images/chart_012.png
figure companion_resources/images/chart_013.png figure companion_resources/images/chart_014.png
figure companion_resources/images/chart_015.png

XYChart

XYChart is a scatter chart. Here is an example of how to use it, together with a screenshot of the application.
import totalcross.sys.Settings;
            import totalcross.ui.*;
            import totalcross.ui.chart.*;
            import totalcross.ui.event.*;
            import totalcross.ui.gfx.Color;
            public class ChartTest2 extends MainWindow
            {
             static
             {
              Settings.useNewFont = true;
          }
          XYChart chart;
          Check showTitle, showHGrids, showVGrids, showYValues;
          ComboBox legendPosition;
          ​
          public ChartTest2()
          {
              super("Chart Test 2", TAB_ONLY_BORDER);
          }
          ​
          public void initUI()
          {
              add(showTitle = new Check("Title"), LEFT, TOP + 2);
              add(legendPosition = new ComboBox(new String[]{"Legend","Right","Left","Top","Bottom"}), AFTER + 2, SAME,PREFERRED,SAME);
              add(showYValues = new Check("YValues"), AFTER+2, SAME);
              add(showHGrids = new Check("HGrids"), LEFT, AFTER + 2);
              add(showVGrids = new Check("VGrids"), AFTER + 2, SAME);
              legendPosition.setSelectedIndex(0);
              add(new Ruler(),LEFT,AFTER+1);
              double[] months = new double[]{100, 200, 300, 400};
              (chart = new XYChart()).series.addElement(new Series("Rice", months, new double[] {100, 102, 104, 106}, Color.YELLOW));
              chart.series.addElement(new Series("Beans", months, new double[] {150, 155, 159, 164}, Color.GREEN));
              chart.series.addElement(new Series("Oil", months, new double[] {130, 137, 143, 150}, Color.RED));
              chart.lineThickness = 2;
              chart.setTitle("Sales Projection");
              chart.setYAxis(0, 200, 10);
              chart.setXAxis(0, 400, 10);
              add(chart, LEFT, AFTER+2, FILL,FILL);
              chart.setBackColor(Color.darker(backColor,16));
              chart.yDecimalPlaces = 0;
              chart.legendPerspective = 6;
          }

          public void onEvent(Event e)
          {
              if (e.type == ControlEvent.PRESSED && (e.target instanceof Check || e.target instanceof ComboBox))
              {
               chart.showTitle = showTitle.isChecked();
               chart.showLegend = legendPosition.getSelectedIndex() != 0;
               chart.legendPosition = getLegendPosition();
               chart.showHGrids = showHGrids.isChecked();
               chart.showVGrids = showVGrids.isChecked();
               chart.showYValues = showYValues.isChecked();
               repaint();
           }
       }
       ​
       private int getLegendPosition()
       {
          switch (legendPosition.getSelectedIndex())
          {
           case 2: return LEFT;
           case 3: return TOP;
           case 4: return BOTTOM;
           default: return RIGHT;
       }
   }
} 
figure companion_resources/images/chart_017.png

ChartData

Represents a table with data that can be displayed together with a chart. Below it is a code sample and a screen with its result. Note that the ChartData grid is integrated with the chart grid.
import totalcross.sys.Settings;
            import totalcross.ui.*;
            import totalcross.ui.chart.*;
            import totalcross.ui.chart.ChartData.ChartDataRow;
            import totalcross.ui.gfx.*;
            import totalcross.util.Properties;
            import totalcross.util.Properties.Str;
            ​
            public class TCTestWin extends MainWindow
            {
             public void initUI()
             {
              double[] xAxis = new double[0];
              Series series = new Series("test", xAxis, new double[0], Color.BLUE);
              int cols = 10, rows = 5;
              XYChart chart = new XYChart();
              ChartDataRow[] data1 = new ChartDataRow[rows];
              ChartDataRow[] data2 = new ChartDataRow[rows];
              ChartData cd1 = new ChartData(chart), cd2 = new ChartData(chart);
              Str[] values;

              setUIStyle(Settings.Android);
              ​
              chart.showHGrids = chart.showVGrids = chart.showYValues = chart.snapToTop = chart.snapToBottom = cd2.snapToBottom = cd1.snapToTop = true;
              chart.yDecimalPlaces = 0; // No decimal places.
              chart.setXAxis(0, 100, 10);
              chart.setYAxis(0, 100, 10);
              chart.showLines = false;
              chart.yValuesSize = fm.stringWidth("99999");
              chart.series.addElement(series);
              cd1.lineColor = cd2.lineColor = Color.BLACK;

              for (int r = 0; r < rows; r++)
              {
               data1[r] = cd1.new ChartDataRow("row " + (r + 1), values = new Str[cols]);
               data2[r] = cd2.new ChartDataRow("row " + (r + 1), values);
               for (int c = 0; c < cols; c++)
               values[c] = new Properties.Str("" + (r + 1) + c);
               cd1.addLine(rows, data1[r]);
               cd2.addLine(rows, data2[r]);
           }              
           ​
           add(cd1,LEFT + 5, TOP + 25, FILL, PREFERRED);
           add(cd2,LEFT + 5, BOTTOM - 25, FILL, PREFERRED);
           add(chart,LEFT + 5, AFTER, FILL, FIT, cd1);
           cd2.bringToFront();
           cd1.bringToFront(); 
           series.xValues = new double[]{10, 20, 30, 40, 50};
           series.yValues = new double[]{10, 30, 50, 70, 90};      
       } 
   }
figure companion_resources/images/chart_data.png

 The Window class

As you already know, a TotalCross program with user interface consists of one and only one main window (a class that directly or indirecly extends MainWindow). This main window can pop up a window, and this new window can pop up another one, and so on. Windows in TotalCross are always modal, therefore, only the last popped up window can receive events and you cannot switch from the topmost Window to the previous without closing the topmost one.
Although the Window class extends Control, you can’t add a Window to a Container. Doing this results in a RuntimeException. To show a window, you must use the method popup() or the method popupNonBlocking().
The following example creates a popup window class:
class TestWindow extends Window
            {
             Button btnHi;
             public TestWindow()
             {
              super("Test",RECT_BORDER); // with caption and borders
              setRect(CENTER,CENTER,Settings.screenWidth/2,Settings.screenHeight/4);
              add(btnHi=new Button("Hi!"),CENTER,CENTER);
          }
          public void onEvent(Event event)
          {
              if (event.type == ControlEvent.PRESSED && event.target == btnHi)
              unpop(); // a WINDOW_CLOSED event will be posted to this PARENT window.
          }
      } 
  
To use it in the normal way (blocking):
public class Launcher extends MainWindow
            {
             Button btn;
             public void onEvent(Event e)
             {
              if (e.target == btn)
              {
               TestWindow tw = new TestWindow();
               tw.popup(); // this line is only executed after the window is closed.
           }
       }
   } 
To use it non-blocking (the execution continues right after the popup command, even with the window still open):
public class Launcher extends MainWindow
            {
             TestWindow tw;
             public void initUI()
             {
              tw = new TestWindow();
              tw.popupNonBlocking(); // this line is executed immediately
          }
          public void onEvent(Event event)
          {
              if (event.target == tw && event.type == ControlEvent.WINDOW_CLOSED)
              {
               // any stuff
               break;
           }
       }
   } 
Blocking popup may be use in InputBox/MessageBox classes, while non-blocking popup is used in MenuBar and other classes. Important note: you can’t use popup() with a delay to unpop it. In this case, the correct would be to use popupNonBlocking():
mb = new MessageBox(...);
            mb.popupNonBlocking();
            Vm.sleep(5000); // or do something else
            mb.unpop(); 
        
If you use popup() in this specific case, the VM will hang.
Some other features of the Window class:
  • Windows can have a title that can be set by the method setTitle(String title) (which calls repaint()) or passed to the constructor.
  • The window border can be selected from one of the multiple styles shown below, by using the setBorderStyle(byte borderStyle) method or passing the desired style to the Window constructor. The parameter value can be NO_BORDER, RECT_BORDER, ROUND_ BORDER, TAB_BORDER, TAB_ONLY_BORDER, HORIZONTAL_GRADIENT, or VERTICAL_ GRADIENT. To retrive it, use getBorderStyle().
  • There are two constructors: the default one, that creates a window with no title and no border, and one constructor with both title and border parameters.
    • Window()
    • Window(String title, byte borderStyle)
  • Windows can be moved around the screen by dragging the window’s title. If the window has no title, it can’t be moved. You can make a titled window unmovable by calling the makeUnmovable() method.
  • The title font can be changed using the setTitleFont() method. To retrive it, use
    getTitleFont(). By default, the font is the one used by the main window, with bold style.
  • Only one control can hold the focus at a time. To change focus to another control, use the setFocus(Control c) method (this can also be done through the requestFocus() method in the totalcross.ui.Control class). When a user types a key, the control with focus gets the key event. Calling this method will cause a FOCUS_OUT control event to be posted to the window’s current focus control (if one exists) and will cause a FOCUS_IN control event to be posted to the new focus control. The getFocus() method returns the control that currently owns the focus.
  • The rectangle area excluding the border and the title is defined as the client rectangle. You can get it with the getClientRect() method.
  • A window can be popped up by calling the popupNonBlocking() method and can be unpopped by calling the unpop() method. The popup process saves the area behind the window that is being popped up and the unpop process restores that area. The unpop() method posts a ControlEvent.WINDOW_CLOSED event to the caller window. The
    popupNonBlocking()
    method can be called like this.popupNonBlocking(). Calling unpop() when only the MainWindow is active does nothing.
  • A window can also be popped up by calling the popup() method, and be unpopped by the same unpop() method described above. The big difference is that in
    popupNonBlocking()
    , the program execution continues to the next line, while in popup(), the program execution is halted and only continues when the popped up window is dismissed. Menu, MessageBox, ComboBox, and ComboBoxDropDown are popped up using popupNonBlocking(), because execution does not need to be halted. InputDialog, Calendar, and Calculator are usually popped up using popup() because the user may want to get the result of the dialog in an easy way.
    You can’t use popup() to popup alternating windows that call each other recursively. For example, suppose that from win1 you call win2.popup(), then at win2 you call unpop() and then win1.popup(). Then, from win1 you do unpop() again and win2.popup(), and so on. This will lead to an OutOfMemoryError on the device due to a native stack overflow. To fix this, just replace the popup by popupNonBlocking().
  • The topmost window (the one who receive events) can be obtained with the static method getTopMost(). To check if this window is the topmost, use the isTopMost() method.
  • Try setGrabPenEvents() for settting to a control to redirect all pen events directly to it. This method speeds up pen event processing. Used in Whiteboard class.
  • You may check if this window is visible using the isVisible() method. This method is inherited from totalcross.ui.Control, but it simply checks if the current window is the topmost one.
  • Each window can have a menu attached by using the method setMenuBar(). The menuBar can be made visible programatically by calling the popupMenuBar() method.
  • Suppose you wish to allow the user to abort a task being executed by pressing. You can use the method pumpEvents() to process all events in the queue. This method is used to implement a blocking Window. Here is an example:
    while(someCondition) 
                 Event.pumpEvents();
             
  • The methods getPreferredWidth() and getPreferredHeight() have a special meaning for the Window class. They return the minimum width/height needed for the correct display of this window. getPreferredWidth() returns the width of the title (if any) plus the width of the border (if any). getPreferredHeight() returns the height of the title (if any) plus the height of the border (if any).
There are some useful protected methods that may be implemented by controls that extend
totalcross.ui.Window
. Those methods are placeholders and there is no need to call the super method.
  • onClickedOutside(int x, int y) This method is used in popup windows. If the user clicks outside the window’s bounds, this method is called giving the absolute coordinates of the clicked point. There are two options:
    If you had handled the action, return true in this method. Otherwise, false must be returned and if the beepIfOut member is true, a beep is played (in other words, beepIfOut can be set to false to disable this beep).
  • onPopup() Called just after the behind contents are saved and before the popup process begin. When this method is called, the topmost window is still the parent of the window being popped up.
  • postPopup() Called after the popup process ended. When this method is called, the popped up window is fully functional. It is a good place to put a control.requestFocus() to make the window popup with the focus in a default control.
  • onUnpop() Called just before the unpop process begin.
  • postUnpop() Called after the unpop process ended. When this method is called, the unpopped window has gone away and the parent window is currently the topmost.
  • postPressedEvent() Posts a ControlEvent.PRESSED event on the focused control.
A very common mistake is to popup a window without setting its bounds. If no bounds are set, the window will not receive events.
The other members that can be used (all public and some protected) of the Window class are explained here:
  • needsPaint true if there are any controls marked for repaint (some area of the window is invalidated).
  • tempTitle A temporary title that will be displayed when the Window pops up. It will be replaced by the original title when it is closed.
  • topmost Stores the topmost window.
  • firstFocus The control that should get focus when a focus traversal key is pressed and none has focus.
  • canDrag (protected) If true and if this is a popup window, the user is allowed to drag the title and make the window move around.
  • cancelPenUp If true, the next PEN_UP event will be ignored. This is used when a PEN_DOWN cancels a flick, or if a drag-scrollable control needs to cancel the next pen_up during a drag-scrolling interaction.
  • gradientTitleStartColor The starting and ending colors used to fill the gradient title.
  • gradientTitleEndColor The starting and ending colors used to fill the gradient title.
  • titleColor The title color. The title color depends on the border type: it will be the foreground color if NO_BORDER is set; otherwise, it will be the background color.
  • titleGap A vertical gap used to increase the title area. Defaults to fmH/2 on Android and 0 on other user interface styles.
  • titleAlign The title horizontal alignment in the window’s title area. It can be LEFT, CENTER, or RIGHT, and you can use an adjustment on the value (E.G.: LEFT+5).
  • headerColorfooterColor Has the header and the footer colors when on Android style and border type is ROUND_BORDER. Not used on other styles.
  • fadeOtherWindows Set to true to make the other windows be faded when the window appears.
  • fadeValue The value used to fade the other windows. Defaults to 128.
  • robot The UIRobot instance that is being used to record or play events.
Never mess with the public member zStack. It is used to store the windows that are currently popped up. It is made public because the totalcross.Launcher class uses it.
Next is explained how controls inside a window are repainted:
  1. The programmer calls the repaint() method of some controls, or a control is clicked and marks itself for repaint.
  2. The damageRect() method in class window creates a rectangle (stored in the paintX, paintY, paintWidth and paintHeight members) with the union of the bounds of all controls marked for repaint.
  3. The next time a VM event is posted, the _doPaint() method of the topmost window is called. This method paints the window’s title/border (if any) and calls the onPaint() method of all containers and controls that lies inside the rectangle area marked for repaint. This explains why nothing in the window is updated when you receive events directly from a native library (the Scanner class, for example). Because the VM is not receiving the event, it never validates the window. In these cases, you must update the window yourself, calling repaintNow() or the validate methods.
Many classes in the totalcross.ui package extend totalcross.ui.Window. Examples of such classes are CalculatorBox and CalendarBox. Other good examples are
ComboBoxDropDown
and MessageBox.
It’s important to be aware that it is not a good practice to create classes that extend Window if they will occupy the whole screen, because they use a lot of memory to store the underlying area. Opening the menu may lead to time-consuming redraws of all opened windows due to out-of-memory problems. In these cases, it is better to use Containers.

 UIColors

This class contains the default colors used in most user interface windows, like CalendarBox, KeyboardBox, CalculatorBox, InputBox, MessageBox, and also the default foreground and background colors of all controls created.
There are no methods in this class, only public static members, which can be freely changed to meet your user interface color scheme. To correctly change the colors for your own, you must do it in the constructor of your application. Note that each member defines the default value for all controls of your application.

Material Icons

What is the Material Icons?

Material Icons are the patterns of icons created by Google - Material Design. They are meant to be used both in your Web projects and in your Android and iOS projects. The Icon Material is available for a wide variety of densities and sizes, over 900 icons, and is also Open Source.

Material Design

It's the visual standard for applications and websites created by Google designers based on the classic principles of good design.

Project Considerations

Material Design seeks to enable a unified experience across platforms and device sizes.

Using Material Icons in TotalCross

All Icons icons are compatible with TotalCross snapshot version 5.0.0.

To use the icons simply import the existing MaterialIcons class into the totalcross.ui package:

    import totalcross.ui.icon.MaterialIcons;

And call them as object:

As much as icon: Icon icon = new Icon(MaterialIcons.values());

As much as MaterialIcon: MaterialIcons._HOME

Creating a List of Material Icons in TotalCross

    public void initUI() {
    int cols =
    (int)
    (Math.min(Settings.screenWidth, Settings.screenHeight)
    / (ICON_WIDTH * Settings.screenDensity));

    Container c =
    new Container() {
    @Override
    public void initUI() {
    for (int i = 0, j = 0; i < MaterialIcons.values().length; i++, j++) {
    Icon icon = new Icon(MaterialIcons.values()[i]);
    icon.setFont(icon.getFont().adjustedBy(10));
    add(
    icon,
    (j % cols) == 0 ? LEFT : AFTER,
    (j % cols) == 0 ? AFTER : SAME,
    PARENTSIZE + (100 / cols),
    DP + ICON_WIDTH);
}
resizeHeight();
}
};
add(c, CENTER, TOP + 100, (int) (cols * ICON_WIDTH * Settings.screenDensity), WILL_RESIZE);
}

See more examples in our Show Case sample on Google Store and GitHub.

It’s a cinch!

 Interface Dialogs

The TotalCross SDK provides some handy interface dialogs, which are windows that handles common user interaction scenarios, like displaying an informative message or requesting a specific user input.
Interface dialogs are pop-up windows that extend the Window class, and just like Window, they are not automatically displayed under creation. To show or hide a dialog you must use Window methods: popup(), popupNonBlocking() and unpop().
For more details about them, check out the package totalcross.ui.dialog JavaDocs.

MessageBox

Simple dialog used to display a text with some user-defined buttons. Useful for displaying informative messages or to make the user take a decision before proceeding (e.g. “Yes/No”, “Ok/Cancel”, “Save/Discard/Cancel”).
Below there is a MessageBox from the old UIGadgets sample using the Android user interface style:
MessageBox has five constructors:
  • MessageBox(String title, String msg) Creates a MessageBox with the given title and message. The message is displayed using a label, and can be displayed in multiple lines if previously parsed with the \n character. It also displays a single <Ok> button to dismiss the window.
  • MessageBox(String title, String text, String[] buttonCaptions) Same as above, but also receives a string array specifying the button captions. A
    PushButtonGroup
    is used to display the buttons, and the method
    getPressedButtonIndex()
    returns the index of the pressed button (where the first one has index 0).
  • MessageBox(String title,String text,String[] buttonCaptions,
    boolean allSameWidth)
    Same as above, but the last parameter indicates that all the buttons have the same width.
  • MessageBox(String title,String text,String[] buttonCaptions,
    int gap,int insideGap)
    Same as the second one, but also receives the gap (space between buttons) and insideGap (space between the button’s text and it’s bounds) to be used by the PushButtonGroup.
  • MessageBox(String title,String text,String[] buttonCaptions,
    boolean allSameWidth,int gap,int insideGap)
    It is the most complete constructor, with all the possible parameters.
The message box is displayed on the center of the device screen, and its bounds are calculated based on the given title, text and buttons. If the text height is above the screen limits, two arrows are added to the message box to allow the text scrolling.
  • MessageBox has the following public fields (omitting some methods from its superclasses):
    • btns The PushButtonGroup with the box buttons.
    • yPosition Defines the y position on screen where the window opens. It can be changed to TOP or BOTTOM. Defaults to CENTER.
    • buttonKeys If you set the buttonCaptions array in the construction, you can also set this public field to an int array of the keys that maps to each of the buttons. For example, if you set the buttons to {"Ok","Cancel"}, you can map the enter key for the Ok button and the escape key for the Cancel button by assigning:
      buttonKeys = new int[]{SpecialKeys.ENTER,SpecialKeys.ESCAPE}; 
                          
      Note that ENTER is also handled as ACTION, since the ENTER key is mapped to ACTION on some platforms.
    • showExceptionTitle Title shown in the showException() dialog for all exceptions shown this way.
  • MessageBox has the following public instance methods (omitting some methods from its superclasses):
    • setText(String text) This method can be used to set the text AFTER the dialog was shown. However, the dialog will not be resized.
    • setIcon(Image icon) Sets an icon to be shown in the MessageBox’s title, at left. It only works if there’s a title. If you really need an empty title, pass as title a string with a couple of spaces, like " ". The icon’s width and height will be set to title’s font ascent.
    • getPressedButtonIndex() Returns the index of the pressed button. This index is zero based (the first element has index 0).
      This method returns -1 if invoked before the window is closed (or if it is closed without any button being pressed). To make sure you’re retrieving the correct value, consider using popup() instead of popupNonBlocking(), or invoke this method only after the window is closed (MessageBox is a Window, so it also posts the event ControlEvent. WINDOW_CLOSED when closed).
    • setTextAlignment(int align) Sets the alignment of the label that displays the text. The argument must be one of the following constants: LEFT, CENTER, or RIGHT. The default alignment is CENTER.
    • setUnpopDelay(int unpopDelay) Automatically unpops the message box after the given time in milliseconds. You must use this method just before displaying the window (either by popup() or popupNonBlocking()). This method actually adds a timer to the message box, invoking the unpop() method when the TimerEvent is triggered. Be sure to learn how the timer works to better understand this method.
    • onEvent(Event e) Handles scroll buttons and normal buttons.
    • setDelayToShowButton(int ms) Calling this method will make the buttons initially hidden and will show them after the specified number of milisseconds. Here’s a sample:
      MessageBox mb = new MessageBox("Novo Tweet!",tweet);
                              mb.setTimeToShowButton(7000);
                              mb.popup();  
                          
    The method setUnpopDelay() does not affect the regular behavior of the message box – the popupNonBlocking() method will not block the program execution and will still return immediately, the popup() method will still block the program execution, and the message box may still be dismissed by the user (e.g. pressing one of its buttons) before the timer finishes.
An interesting feature of the message box is that you may create it with no buttons, just passing the null value for the constructor’s argument buttonCaptions. However, a message box created with no buttons does not provide a default way of being dismissed by the user. You must dismiss it programatically, by invoking unpop(), using setUnpopDelay() or handling events (e.g. you may handle pen events to make it unpop after the user touches the screen).
The MessageBox class has a handy method to debug your application:
  • showException(Throwable t, boolean dumpToConsole) Immediately displays a message box showing the given throwable name, message, and its stack trace. This information is dumped to the debug console if the field dumpToConsole is true.
If you use an IDE with customizable templates for automatic code generation (like Eclipse), try changing the template for try/catch blocks to call MessageBox.showException() instead of Throwable.printStackTrace().

InputBox

Simple dialog used to get a text input from the user. It contains a label to display some text, an edit to receive the user input, and some user-defined buttons. Basically it’s like a message box with an edit.
Below there is a InputBox from the old UIGadgets sample using the Android user interface style:
figure companion_resources/images/inputbox_001.png
It has three constructors:
  • InputBox(String title, String text, String defaultValue) Creates an input box with the given title, text, a default value for the edit, and two buttons: <Ok> and <Cancel>.
  • InputBox(String title,String text,String defaultValue,
    String[] buttonCaptions)
    Same as the above, plus a string array specifying the buttons captions. A PushButtonGroup is used to display the buttons, and the
    getPressedButtonIndex()
    method returns the pressed button index.
  • InputBox(String title,String text,String defaultValue,
    String[] buttonCaptions,boolean allSameWidth,int gap,int insideGap)
    The most complete version, where allSameWidth indicates that all the buttons have the same width, gap is the space between buttons, and insideGap is the space between the button’s text and it’s bounds.
Unlike the message box, the argument buttonCaptions cannot have a null value.
The input box is displayed on the center of the device screen, and its bounds are calculated based on the given title, text, edit, and buttons. If the text height is above the screen limits, two arrows are added to the input box to allow the text scrolling. And its edit receives the focus when the input box is popped up.
The InputBox class provides the following public attributes and methods (omitting some fields from its superclasses):
  • openKeyboardOnPopup Set to true to automatically open the keyboard once the InputBox is open. Since this is a static member, it is valid for all InputBoxes.
  • yPosition Defines the y position on screen where the window opens. Can be changed to TOP or BOTTOM. Defaults to CENTER. The image above shows a InputBox opened at the bottom.
  • buttonKeys If you set the buttonCaptions array in the construction, you can also set this public field to an int array of the keys that maps to each of the buttons.
  • setTextAlignment(int align) Sets the alignment for the text. The parameter must be CENTER (default), LEFT, or RIGHT.
  • getPressedButtonIndex() Returns the index of the pressed button. This index is zero based (the first element has index 0). This method returns -1 if invoked before the window is closed (or if it is closed without any button being pressed). To make sure you’re retrieving the correct value, consider using popup() instead of popupNonBlocking(), or invoke this method only after the window is closed (InputBox is a Window, so it also posts the event ControlEvent.WINDOW_CLOSED when closed).
  • getEdit() Returns a reference to this input box’s edit, so you can change its properties.
  • getValue() Returns a string with the edit’s text.
  • setValue(String value) Sets the edit with the given value.

KeyboardBox

Dialog that displays a virtual keyboard that can be used to handle text input either by the device’s keyboard or by pen events on the virtual keyboard on devices with touchscreen.
Unlike other dialogs, the KeyboardBox constructor does not receive any arguments, and it does not provide any methods for its manipulation. So how does it work?
When the keyboard box is popped up, it gets the control of the topmost window that currently holds the focus. The control is shown at the top of the keyboard box, and any text input received is passed to the control as a key event. If the virtual keyboard is used, the keyboard box handles the pen event, converting it to a key event before passing to the target control.
The edit and multi edit controls may use the keyboard box for text input.
Below there is a KeyboardBox from the old UIGadgets sample using the Android user interface style:
figure companion_resources/images/keyboardbox_001.png

CalculatorBox

A dialog with a simpler calculator. It allows you to enter two numbers, select an operation and calculate the result. You may also paste the result or the first operand.
This class is used by the Edit class when its mode is set to CURRENCY and displays a calculator with six basic operations and a numeric pad. Here is a sample from the old UIControls sample (now inside the ui package from the TotalCrossAPI sample):
figure companion_resources/images/calculator_001.png
This class has the following public attributes, constructors, and methods (excluding some fields from its superclasses):
  • edNumber The edit used to show the number.
  • actions Strings used to display the action messages. You can localize these strings if you wish. Its default value is {"Clear","Ok","Cancel"}.
  • defaultTitle A static field that defines the default title for all calculator boxes, which is Numeric Pad.
  • optionalValue Defines an optional character to be used in the CalculatorBox. Replaces the decimal separator / 00 character.
  • maxLength The maximum length for the edit that will be created.
  • cOrig The control that had focus when the CalculatorBox was popped up.
  • defaultValue The default value of the edit.
  • keepOriginalValue Set to true to don’t replace the original value in the Edit if the user pressed Ok.
  • showNextButtonInsteadOfClear Set to true to replace the Clear button by the Next button. This button is equivalent to the Ok button, but it also changes the focus to the next field. The user can still clean the edit by clicking the backspace << button. The default behaviour calls moveFocusToNextControl(). You can change it by overriding the method gotoNext().
  • CalculatorBox() Constructs a CalculatorBox with the 6 basic operations visible.
  • CalculatorBox(boolean showOperations) Constructs a CalculatorBox with the 6 basic operations hidden if the parameter is false. In this case, it will become a numeric box.
  • clear(boolean requestFocusOnOper1) Clears everything in this calculator.
  • getAnswer() Returns a string with the answer the user selected to be pasted (the result, the first operand, or null if the user canceled).

CalendarBox

Displays a calendar where a date can be chosen. It pops up with the current day as default and the user can scroll through months or years. It uses the Date class for all operations. When a day is selected the calendar is closed and you may retrieve a Date object representing the chosen date.
Instead of creating a new instance (which consumes memory), you may use the Edit’s static field calendar.
If there is something in the edit box which poped up the calendar, the clear button will clear it. Cancel will leave whatever was in there.
The month can be changed via keyboard using the left/right keys, and the year can be changed using up/down keys.
Here is a sample from the old UIControls sample (now inside the ui package from the TotalCrossAPI sample):
figure companion_resources/images/calendar_001.png
This class has the following public attributes, one omitted default constructor, and methods (excluding some fields from its superclasses):
  • canceled true if the user had canceled without selecting.
  • weekNames The 7 week names painted in the control. It defaults to
    {"S","M","T","W","T","F","S"}
    .
  • todayClearCancel The labels for Today, Clear, and Cancel. It defaults to
    {"Today","Clear","Cancel"}
    .
  • yearMonth The labels between the arrows for year and month. It defaults to {"year","month"}.
  • getSelectedDate() Returns a Date object representing the selected date, or null if the calendar is canceled.
  • setSelectedDate(Date d) Changes this calendar box current date by the given one. If the given date is null, the current date is set to today.
To correctly retrieve the selected date, you can handle the ControlEvent.PRESSED event posted by the calendar, and call getSelectedDate().
Sample code:
CalendarBox calendar = new CalendarBox();
            ​
            public void initUI()
            {
             calendar.popup();
         }
         ​
         public void onEvent(Event event)
         {
             if (event.type == ControlEvent.PRESSED && event.target == calendar)
             {
              Date date = calendar.getSelectedDate();
              String text = (date == null)? "No date selected" : date.toString();
              new MessageBox("Selected Date", text).popup();
          }
      }
  

ColorChooserBox

Shows a color dialog that can be used to select a color. There are several ways to choose a color:
  • Using a color matrix.
  • Using a websafe palette.
  • Writting the red, green, and blue components.
  • Writting the color in hexdecimal.
Here’s a sample code:
ColorChooserBox ccb = new ColorChooserBox(getBackColor());
            ccb.popup();
            if (ccb.choosenColor != -1) // user pressed cancel?
            int color = ccb.choosenColor; // no, color was selected 
        
The ColorChooserBox looks like the following images taken from the old UIGadgets sample using Android user interface style:
figure companion_resources/images/colorchoser_001.png figure companion_resources/images/colorchoser_002.png

ControlBox

A popup window that displays any control given as parameter to the constructor To add more than one control, use a container. Here is a sample from Litebase AllTests:
figure companion_resources/images/controlbox_001.png

FileChooserBox

A class that shows all folders from a startup one to allow the user select a file or a folder. The file tree is mounted on demand to speed up the process.
Here’s a list of customizations you can do:
  • You can set a path to be selected initially by setting the initialPath property.
  • Set the defaultButton property to allow the selection of an item doing a double-click on it.
Here’s a sample of how to use it:
try
            {
             FileChooserBox w = new FileChooserBox("Select the folder",new String[]{" This one "," Cancel "}, 
             new FileChooserBox.Filter()
             {
               public boolean accept(File f) throws IOException
               {
                return f.isDir(); // will only list folders. you may filter by other file types too
            }
        });
        w.mountTree(Settings.appPath,1);
        w.popup();
        return w.getPressedButtonIndex() == 0 ? w.getAnswer() : null;
    } 
    catch (IOException e)
    {
     return null;
 } 
The section Tree↑ from chapter “Some Advanced Controls” shows some images of its usage.
This class use a nested interface called FileChooserBox.Filter. This is necessary to indicate that a filter must have the method accept(File f), which must return true if the file is to be added to the tree.

ProgressBox

This class implements a message box that shows a spinner at the left of the text. You can set the spinner color and type before constructing the progress box (usually you do this in your application’s constructor, and not for each progress box created).
Here’s a sample:
ProgressBox pb = new ProgressBox("Message","Loading, please wait...",null);
            pb.popupNonBlocking();
            ... lengthy task
            pb.unpop(); 
        
In the old UIControls sample (now inside the ui package from the TotalCrossAPI sample), there is some examples using ProgressBox. The images order follow the buttons order to show the examples:
figure companion_resources/images/progressbox_001.png
figure companion_resources/images/progressbox_002.png figure companion_resources/images/progressbox_003.png
figure companion_resources/images/progressbox_004.png figure companion_resources/images/progressbox_005.png

TimeBox

Class used to input a time from the user. Correctly handles the AM/PM depending on
Settings.is24Hour
.
When the window closes, a PRESSED event is sent to the caller, and the time can be retrieved using getTime().
The time can be entered also using the arrow keys and by typing the numbers directly.
Here’s a sample:
TimeBox tb;
            public void initUI()
            {
             try
             {
              (tb=new TimeBox()).popupNonBlocking();
          }
          catch (Exception e)
          {
              e.printStackTrace();
          }
      } 
      ​
      public void onEvent(Event e)
      {
         if (e.type == ControlEvent.PRESSED && e.target == tb)
         Vm.debug("ret: "+tb.getTime());
     } 
 
It looks like the following image taken from the old UIControls sample (now inside the ui package from the TotalCrossAPI sample):
figure companion_resources/images/timebox_001.png

 Image

Image is a rectangular image, which you can draw into or copy to a surface (using a Graphics object). They are always 24 bpp, and TotalCross supports only the PNG and JPEG formats when running on the TCVM.
However, you may still use GIF and BMP files on your application, because these formats are also supported when running on Java, and the TotalCross deployer automatically converts those files to 24 bpp PNG files, which are then packaged with your application (along with any other required resources). The deployed PNG may contain transparency information which is correctly handled.
Image objects cannot be directly added to the user interface because they are not controls (i. e. the Image class does not extend the Control class). To display an image on the user interface, you may either use the Graphics object to draw the image on the screen, or use a control that better suits your needs, like ImageControl or Button (both described at the user interface section of this document).
Some transformation methods return a new instance of this image while others apply to the current instance. To preserve an image with a single frame, use getFrameInstance(0).
TotalCross does not support grayscale PNG with alpha-channel. Convert the image to true-color with alpha-channel and it will work fine (the only backdraw is that the new image will be bigger).
Image constructors:
  • Image(int width, int height) Creates an Image object with the given width and height. The new image has the same color depth and color map of the default drawing surface. Here is an example of use:
    Image img = new Image(100,100);
                    Graphics g = img.getGraphics();
                    g.backColor = Color.WHITE;
                    g.fillRect(25,25,50,50);
                    ...
                    Graphics screenG = getGraphics();
                    screenG.drawImage(img,CENTER,CENTER);  
                
  • Image(byte[] fullDescription) Creates an Image object from the given byte array, which must specify the whole image, including its headers. Use only JPEG or PNG images on the devices (GIF and BMP are supported on the desktop only). Here is a code example:
    // create the image and fill it with something
                    Image img = new Image(160,160);
                    Graphics g = img.getGraphics();
                    for (int i =0; i < 16; i++)
                    {
                     g.backColor = Color.getRGB(10*i,10*i,10*i);
                     g.fillRect(i*10,0,10,160);
                 }  
                 // save the bmp in a byte stream
                 ByteArrayStream bas = new ByteArrayStream(4096);
                 DataStream ds = new DataStream(bas);
                 int totalBytesWritten = img.createBmp(ds);
                 // parse the saved bmp
                 Image im = new Image(bas.getBuffer()); // Caution! the buffer may be greater than totalBytesWritten, but when parsing theres no problem.
                 if (im.getWidth() > 0) // successfully parsed?
                 {
                     getGraphics().drawImage(im,CENTER,CENTER);
                     Vm.sleep(2000);
                 }  
             
Caution: if reading a JPEG file, the original array contents will be changed!
  • Image(String path) Attempts to read the contents of the file specified by the given path, creating an Image object from the bytes read. The path given is the path to the image file. The file must be in 2, 16, 256, 24 bpp color compressed (RLE) or uncompressed BMP bitmap format, a PNG file, a GIF file, or a JPEG file. If the image cannot be loaded, an ImageException will be thrown.
  • Image(Stream s) Attempts to read the contents of the given stream, and create an Image object from the bytes read. Loads a BMP, JPEG, GIF, or PNG image from a stream. Note that GIF and BMP are supported only on the desktop. Note that all the bytes of the given stream will be fetched, even those bytes that may follow the image.
The usage of this last constructor with connection oriented streams (like socket) is not advised.
  • If you want to check if a specific file is supported by the platform at runtime, you may use the static method Image.isSupported(String filename). PNG or JPEG are always supported. GIF and BMP are supported on JavaSE only.
  • To retrieve the image dimensions, you may use the methods getWidth() and
    getHeight()
    . You can check if the image is ok by comparing these values with zero.
  • The method getGraphics() returns the Graphics object used by this image, which provides several methods that may be used for drawing in this image.
  • You may change all pixels of the same color by another color with the method changeColors (int from, int to). The current value of the transparent color is not changed. Using this routine, you can change the colors to any other you want. Note this replaces a single solid color by another solid color. If you want to change a gradient or colorize an image, use the applyColor(int color) method instead, which applies the given color RGB values to all pixels of this image, preserving the transparent color and alpha channel, if set.
The deployer also convert animated GIFs into multi-frame PNGs – which are regular PNG files that contains all frames from the original GIF, along with the number of frames – to be packaged with the application’s tclass file.
In this case, you may use the method getFrameCount() to check if the loaded image contains more than one frame.
However, you may want to load an actual PNG or JPEG file created in multi-frame format to display an animation. In this case, the number of frames contained in the file will be unknown and getFrameCount() will return 1.
To set the actual number of frames of the image, you must use the method setFrameCount (int n), which sets the total number of frames of the image by the given one, but only if the total image width (including all frames) is divisible by the given value.
The image’s frame count cannot be changed if its value is already higher than 1. In this case, the setFrameCount() method simply returns without doing anything.
The following methods should be used only on multi-framed images.
  • getCurrentFrame() Returns the index of the current visible frame.
  • setCurrentFrame(int nr) Sets the given frame index as the current frame, moving its contents to the set of visible pixels. If the given index is negative, the last frame is set as the current frame; if it’s higher than the number of frames, the first one is set instead.
  • nextFrame() Sets the next frame as the current one.
  • prevFrame() Sets the previous frame as the current one.
Both nextFrame() and prevFrame() treat the multi-framed image as a circular list, looping back to the first frame if moving forward from the last frame, or to the last frame if moving backwards from the first frame.
The Image class also provides the methods that creates a new Image object to be changed and returned, instead of changing the original instance:
  • getScaledInstance(int newWidth, int newHeight) Returns a scaled instance of this image. The arguments are the new dimensions for this image in pixels. The algorithm used is the replicate scale: not good quality, but fast.
  • scaledBy(double scaleX, double scaleY) Returns a scaled instance of this image. The new dimensions are calculated based on this image’s dimensions and the given proportions. The algorithm used is the replicate scale: not good quality, but fast. The given values must be > 0.
  • getSmoothScaledInstance(int newWidth, int newHeight, int backColor) Returns a scaled instance of the image using the area averaging algorithm. Transparent pixels are replaced by backColor, which produces a smooth border. Example:
    Image img2 = img.getSmoothScaledInstance(200,200, getBackColor());
                
    On device and JavaSE it uses a Catmull-rom resampling. The reason is that the Catmull-rom consumes more memory and is also slower than the area-average, although the final result is much better.
  • smoothScaledBy(double scaleX, double scaleY, int backColor) Returns a scaled instance of this image. The new dimensions are calculated based on this image’s dimensions and the given proportions. The given values must be > 0. The transparent pixels are replaced by backColor, which produces a smooth border. Example:
    Image img2 = img.smoothScaledBy(0.75,0.75, getBackColor()); 
                
  • getRotatedScaledInstance(int scale, int angle, int fillColor)
    Returns a rotated and/or scaled version of this image. A new Image object is returned which will render the image at the specified scale ratio and rotation angle. After rotation, the empty parts of the rectangular area of the resulting image are filled with the fill color. If color is -1, then the fill color is the transparent color, or white if none. The new image will probably have a different size of the original image. In multi-framed images, each image is rotated/scaled independently.
    scale is a number greater than or equal to 0 stating the percentage of scaling to be performed. 100 is not scaling, 200 doubles the size, and 50 shrinks the image by 2. angle is the rotation angle, expressed in trigonometric degrees and fillColor is the fill color (-1 indicates the transparent color of this image or Color.WHITE if the transparentColor was not set).
    Do not use this method for scaling only, because the scaling methods are faster. If you need a smooth scale and rotate, scale it first with smoothScaledBy() or getSmoothScaledInstance() and rotate it without scaling (or vice-versa).
  • getTouchedUpInstance(byte brightness, byte contrast) Returns a touched-up instance of this image with the specified brightness and contrast.
    brightness
    is a number between -128 and 127 stating the desired level of brightness. 127 is the highest brightness level (white image), while -128 is no brightness (darkest image). contrast is a number between -128 and 127 stating the desired level of contrast. 127 is the highest contrast level, while -128 is no contrast.
    The methods getSmoothScaledInstance() and smoothScaleBy() uses the area averaging algorithm instead of the replication algorithm used by scaleBy() and getScaledInstance(). Although slower, the area averaging algorithm provides better results. You may now create only 320x320 images for your application, and smoothly resizes it to the target resolution, instead of providing one image per resolution.
    Images with anti-aliased borders produce better results because of the extra argument for the background color.
  • smoothScaledFixedAspectRatio(int newSize,boolean isHeight,
    int backColor)
    Returns the scaled instance using fixed aspect ratio for this image, given the scale arguments. The given values must be > 0. This method is useful to resize an image, specifying only one of its sides: the width or the height. The other side is computed to keep the aspect ratio. newSize is the new size (width or height) for the image, if isHeight is true, newSize is considered as the new height of the image; if false, newSize is considered the new width of the image, and backColor is the background color to be used as transparent pixel (for PNG images with alpha-channel, use -1). Example:
    Image img2 = img.smoothScaledFixed(fmH, true, -1); 
                
  • getFadedInstance(int backColor) Creates a faded instance of the image, interpolating all pixels with the given background color. The pixels that match the transparent color will not be changed.
  • getFrameInstance(int frame) In a multi-framed image, returns a copy of the given frame. In a single-framed image, gets a copy of the image.
  • smoothScaledFromResolution(int originalRes, int backColor) Returns a smooth scaled instance of this image with a fixed aspect ratio based on the given resolution (which is the resolution that you used to MAKE the image). The target size is computed as image_size*min(screen_size)/original_resolution. originalRes is the original resolution that the image was developed for (it’s a good idea to create images for 320x320 and then scale them down) and backColor is the background color.
And finally, to save your Image object, you may use one of the methods below:
  • createPng(Stream s) Attempts to write this image as a 24 bpp PNG file on the given stream (if useAlpha is true, it saves as 32 bpp). If you’re sending the PNG through a stream but not saving it to a PDBFile, you can use this method. If you’re going to save it to a PDBFile, then you must use the saveTo() method.
  • saveTo(PDBFile cat, String name) Writes this image as a 24 bpp PNG file on the currently selected record of the given PDBFile, using the given name. The stored image size is limited to near 64 Kb. Note that a stored image size has no relation to its size in pixels. For example, a 1300x1200 completely-white PNG file takes 7 Kb of storage size but 6 MB of RAM when loaded.
    • The PDBFile can save multiple images, but the record must be prefixed with the image’s name and must be sorted.
    • This method finds the exact place where to insert the PNG and puts it there.
    • If you want to create a PNG to be transfered by a stream to serial or socket then you must use the method createPng() instead.
    • If a record with this name already exists, it will be replaced.
    • The name is always converted to lowercase and the method makes sure that PNG is appended to it.
    • To get the list of images in a PDBFile, just do a readString() at the beginning of each record.
    • To retrieve the image, use the loadFrom(PDBFile cat, String name) method.
    Here is a sample code:
    // create the image and paint over it
                        Image img = new Image(100,100);
                        Graphics g = img.getGraphics();
                        g.backColor = Color.getRGB(100,150,200);
                        g.fillRect(25,25,50,50);
                        g.foreColor = Color.WHITE;
                        g.drawCircle(50,50,20);  // create the PDBFile to save the image. You must change CRTR to match your apps creator ID
                        String pdbName = "images.CRTR.TYPE";
                        PDBFile pdb = new PDBFile(pdbName, PDBFile.CREATE);
                        img.saveTo(pdb, "boxcircle.png");
                        pdb.close();  // load the previously created image
                        PDBFile pdb = new PDBFile(pdbName, PDBFile.READ_WRITE);
                        add(new ImageControl(Image.loadFrom(pdb,"boxcircle.png")),CENTER,CENTER);
                        pdb.close();  
                    
    Here’s a code that lists the images in a PDB (saved using this method).
    public static String[] list(PDBFile cat) throws IOException  
                        {
                         DataStream ds = new DataStream(cat);
                         int n = cat.getRecordCount();
                         String[] names = new String[n];
                         for (int i =0; i < n; i++)
                         {
                          cat.setRecordPos(i);
                          names[i] = ds.readString();
                      }
                      return names;
                  } 
              
Some other Image public methods (omitting the ones from its superclass):
  • getPixels() Used only on the desktop to get the image’s pixels; NOT AVAILABLE on the device (it will throw a NoSuchMethodError).
  • getX()getY() Returns 0.
  • equals(Object o) Returns true if the given Image object has the same size and RGB pixels of the original one. The alpha-channel is ignored.
  • applyColor2(int color) Applies the given color RGB values to all pixels of this image, preserving the transparent color and alpha channel, if set. This method is used to colorize the Android buttons.
Here’s an example of how to create buttons for several resolutions based on a 320x320 images: (adapted from the old UIGadgets sample)
public void initUI()
            {
             setTitle("ImageButton resolution scale");
             String[] imageNames = {"clear.gif", "go.gif"};
             int imgRes = 320;
             int targetRes[] = {160, 176, 240, 320};
             int backColor = getBackColor();
             int coordX = LEFT;
             ​
             try
             {
              for (int i = imageNames.length - 1; i >= 0; i--)
              {
               Image img = new Image(imageNames[i]);
               int imgWidth = img.getWidth();
               int coordY = TOP;
               for (int j = targetRes.length - 1; j >= 0; j--)
               {
                double factor = (double) targetRes[j] / (double) imgRes;
                Image img2 = img.smoothScaledBy(factor, factor, backColor);
                Button btn = new Button(img2);
                btn.setBorder(Button.BORDER_NONE);
                add(btn, coordX, coordY);
                coordY += img2.getHeight() + 5;
            }
            coordX += imgWidth + 5;
        }
    }
    catch (Exception e)
    {
      MessageBox.showException(e, true);
  }
}
Another example with an animated GIF: (adapted from the old GifAnimatedTest sample now inside the ui package from the TotalCrossAPI sample):
public void initUI()
            {
             try
             {
              img = new Image("alligator.gif");
              imgCtrl = new ImageControl(img);
              add(imgCtrl, CENTER, CENTER);
              addTimer(200);
          }
          catch (Exception e)
          {
              MessageBox.showException(e, true);
          }
      }
      public void onEvent(Event event)
      {
         if (event.type == TimerEvent.TRIGGERED)
         {
          img.nextFrame();
          imgCtrl.repaintNow();
      }
  }
Note that it will work in the same way on desktop or on device.

 Camera

This class is used to enable the camera of the underlying device. The following platforms are supported: Android and iOS. It is not possible to use the webcam on PC platforms (JavaSE, Windows XP, Vista, Seven, 8, and Linux).
Note that you can easily rotate the image to put it in portrait mode, using the Image.
getRotatedScaledInstance()
method, after retrieving the image. You may change the following options: initialDir, defaultFileName (must end with .jpg), and resolutionWidth x resolutionHeight (possible values are 320x240, 640x480, 1024x768, 2048x1536; different values defaults to 640x480). All other options are ignored.
On Android you can set the defaultFileName, stillQuality, resolutionWidth and resolutionHeight. All other options are ignored. You can call the
getSupportedResolutions() method to see the resolutions that are available on the device.
On iOS there’s no way to return the supported resolutions; it will take a photo using the default camera’s resolution, and then will resize to the resolution defined in resolutionWidth x resolutionHeight, keeping the camera’s aspect ratio. On iOS you can specify the
defaultFileName
with a path or just the name, or use a system-generated name. On iOS it is not possible to record a movie, only to take pictures.
This class only has de default constructor. The other interesting fields are:
  • title The title to display in the window opened for the camera.
  • stillQuality Defines the quality of the image. It can be equal to
    CAMERACAPTURE_STILLQUALITY_DEFAULT (default quality),
    CAMERACAPTURE_STILLQUALITY_LOW (low quality),
    CAMERACAPTURE_STILLQUALITY_NORMAL (normal quality), or
    CAMERACAPTURE_STILLQUALITY_HIGH (high quality).
  • videoType Can be one of
    CAMERACAPTURE_VIDEOTYPE_ALL (produces video clips that match video profiles, using just the video resolution for the match criteria, the default value)
    CAMERACAPTURE_VIDEOTYPE_STANDARD
    (produces high-quality video clips used for home movies and e-mail video messaging, using a video encoder such as the Windows Media encoder), or
    CAMERACAPTURE_VIDEOTYPE_MESSAGING (Produces video clips used for Multimedia Messaging Service (MMS) video messaging, which require a video encoder that conforms to the 3rd Generation Partnership Project (3GPP) specification on
    http://go.microsoft.com/fwlink/?LinkId=32710).
  • videoTimeLimit Maximum time limit for recording a video.
  • captureMode Can be one of
    CAMERACAPTURE_MODE_STILL (only picture, the default value),
    CAMERACAPTURE_MODE_VIDEOONLY (no sound), or
    CAMERACAPTURE_MODE_VIDEOWITHAUDIO (video and sound).
  • allowRotation Use this on Android only. If false, the camera buttons will be on landscape. If true, the camera buttons will follow the device current rotation when the camera is opened.
The class Camera only has one method:
  • click() Takes a photo or records a video based on the members set. It returns a string with the file name where the image or video is located, or null if the user canceled.
  • getSupportedResolutions() Gets the supported resolutions on the current device.

Cards

Applications consist of displaying data in containers with similar styles. These containers are used to store information for each item. For this, you have the cards. From this differentiated layout, based on CardView, it is intended to create information in the standard and consistent containers across the platform.

Creating Cards

The Card component is available from version 5.0 - M1 of Totalcross. To create them just create a class that inherits from Container.

There are four types:

To see examples of each, just click on its name.

Card Samples

To see examples of how to build the cards, just click here or download our Showcase!

To understand better we'll see a little bit of code.


Weather Card

As the name suggests, the Weather card is usually used to show the climate of a particular location. To create it we need a class that inherits from Container (as we said at the beginning), an ImageControl, two Containers and two labels. So just mount within the initUI(), as we can see below.

                public void initUI() {  

                try {
                //Let's set the basic characteristics as the background color
                setBackColor(Color.WHITE);  
                setBorderStyle(BORDER_SIMPLE);
                borderColor = 0xFFFFFF;

                //Now let's create the first container and call it cont. Let's position it on the left side of the screen.
                cont = new Container();
                cont.setBackColor(0x215968);

                //Let's create cont2, this is the Container on the right side.
                cont2 = new Container();
                add(cont, LEFT, TOP, PARENTSIZE+50, PARENTSIZE); //Here we place the cont on the left side.
                add(cont2, RIGHT, TOP, PARENTSIZE+50, PARENTSIZE); // And the cont2 on the right side.

                //Now let's instantiate our ImageControl to show the image of the weather.
                imgIcon = new ImageControl(new Image("images/partly-cloudly.png").hwScaledFixedAspectRatio((int) (fmH * 5), true));

                //Here we will instantiate our Label with the number of the climate, by uses source like Lato Medium and say the color.
                lbValue = new Label("22°");
                lbValue.setFont(Font.getFont("Lato Medium", false, lbValue.getFont().size + 30));
                lbValue.setForeColor(0x215968);

                 //Let's do the same with the Label that contains the text.
                lbText = new Label("Partly Cloudly");
                lbText.setFont(Font.getFont("Lato Medium", false, lbText.getFont().size + 10));
                lbText.setForeColor(0x215968);

                // Now let's add them to the containers. The image on the left side and the other components on the right side.
                cont.add(imgIcon, CENTER, CENTER, PREFERRED, PREFERRED);
                cont2.add(lbValue, CENTER, CENTER - 30, PREFERRED, PREFERRED);
                cont2.add(lbText, CENTER, AFTER, PREFERRED, PREFERRED);

            }catch (ImageException | IOException e) {
            e.printStackTrace();
        }
    }

The exemple above will show something like this image.


Social Cards

The cardSocial is, as suggested in the name, for social networking links. To reuse the data of a class that can be contained in the container (click here) and the social networking buttons that you want the case (in the case that presents us, we chose 3 social networks, that is, three buttons). Let's understand better buy the code:

        public void initUI() {
        //Let's start the navigation, the border and the style of the border
        setBackColor(Color.WHITE);
        setBorderStyle(BORDER_SIMPLE);
        borderColor = 0xFFFFFF;

        try {
        //we will instantiate the Buttons that we create, passing in them the image, size and style of border.
        btFacebook = new Button(new Image("images/fb_icon_40.png").hwScaledFixedAspectRatio((int)(fmH*1.5), true));
        btFacebook.setBorder(Button.BORDER_NONE); //esse é o button do facebook
        btInstagram = new Button(new Image("images/insta_icon_40.png").hwScaledFixedAspectRatio((int)(fmH*1.5), true));
        btInstagram.setBorder(Button.BORDER_NONE); //do instagram
        btTwitter = new Button(new Image("images/tt_icon_40.png").hwScaledFixedAspectRatio((int)(fmH*1.5), true));
        btTwitter.setBorder(Button.BORDER_NONE); //e do twitter

        //Now we will add them to the screen, setting your position. 
        add(btInstagram, CENTER, CENTER, PREFERRED, PREFERRED); // Primeiro adc o button do centro
        add(btFacebook, BEFORE-fmH*18, CENTER, PREFERRED, PREFERRED); //agora colocamos um antes do button central
        add(btTwitter, AFTER+fmH*18, CENTER, PREFERRED, PREFERRED, btInstagram); // e um após o button central

    } catch (ImageException | IOException e) {
    e.printStackTrace();
} 
}

The exemple above will show something like this image.


Profile Card

This is the longest card, although simple. It is used, as suggested in the name, to show user profiles. To create it we need two Containers (cont and cont2), nine Labels (lbHour, lbDate, lbDay, lbInbox lbDraft, lbSpam, lbInboxValue, lbDraftValue, lbSpamValue), three Buttons (btSend, btAttach, btOthers) and an ImageControl (imgProfile) . After creating the components, let's begin to build our interface


      public void initUI() {

      try {
      // let's start by setting the basic settings: background color, border type and color
      setBackColor(0xFFFFFF);
      setBorderStyle(BORDER_SIMPLE);
      borderColor = 0xFFFFFF;

      // Let's instantiate the first Container and start building what's going to have "inside" it
      cont =
      new Container() {
      @Override
      public void initUI() {
      setBackColor(0x215968);

      try {

      // And now we go for an image on the screen, the profile image of the user. Let's instantiate the imgProfile and set the path of the image and its size. Let's also put it in the center (centerImage = true)
      imgProfile =
      new ImageControl(
      new Image("images/profile.png")
      .hwScaledFixedAspectRatio((int) (Settings.screenDensity * 56), true));
      imgProfile.centerImage = true;
  } catch (IOException e) {
  // All Auto-generated catch block
  e.printStackTrace();
} catch (ImageException e) {
// All Auto-generated catch block
e.printStackTrace();
}

// Now let's start instantiating the Labels, that is, the texts present in Container cont. Let's say what is the text and the font size, color and type
lbHour = new Label("12:00");
lbHour.setFont(Font.getFont("Lato Medium", false, lbHour.getFont().size + 20));
lbHour.setForeColor(Color.WHITE);

// let's repeat this for all Labels
lbDate = new Label("13 April 2018");
lbDate.setFont(Font.getFont("Lato Medium", false, lbDate.getFont().size + 8));
lbDate.setForeColor(Color.WHITE);

lbDay = new Label("Saturday");
lbDay.setFont(Font.getFont("Lato Medium", false, lbDay.getFont().size + 8));
lbDay.setForeColor(Color.WHITE);

// And now let's add:
// First we add the image, saying that it will be in the center and placing according to the pixel density
add(imgProfile, LEFT + 50, CENTER, (int) (Settings.screenDensity * 64), DP + 64);
// And then we'll add the Labels, telling the site
add(lbHour, AFTER + 50, CENTER, PREFERRED, PREFERRED);
add(lbDay, AFTER + 50, TOP + 10, PREFERRED, PREFERRED);
add(lbDate, AFTER + 50, BOTTOM - 10, PREFERRED, PREFERRED, lbHour);
}
};
// And finally we add the container and we tell him the manhole (On the top, the left)
add(cont, LEFT, TOP, PARENTSIZE, PARENTSIZE + 40);

// Now let's instantiate the second Container and let's say the background color and add it to the screen
cont2 = new Container();
cont2.setBackColor(0xD3D3D3);

add(cont2, LEFT, AFTER, PARENTSIZE, PARENTSIZE + 30);

// Next we'll start to instantiate the Labels, say their text, font type and color
lbInboxValue = new Label("8");
lbInboxValue.setFont(Font.getFont("Lato Medium", false, lbInboxValue.getFont().size + 5));
lbInboxValue.setForeColor(0x215968);

lbInbox = new Label("Inbox");
lbInbox.setFont(Font.getFont("Lato Medium", false, lbInbox.getFont().size));
lbInbox.setForeColor(0x215968);

lbDraftValue = new Label("0");
lbDraftValue.setFont(Font.getFont("Lato Medium", false, lbDraftValue.getFont().size + 5));
lbDraftValue.setForeColor(0x215968);

lbDraft = new Label("Draft");
lbDraft.setFont(Font.getFont("Lato Medium", false, lbDraft.getFont().size));
lbDraft.setForeColor(0x215968);

lbSpamValue = new Label("1");
lbSpamValue.setFont(Font.getFont("Lato Medium", false, lbSpamValue.getFont().size + 5));
lbSpamValue.setForeColor(0x215968);

lbSpam = new Label("Spam");
lbSpam.setFont(Font.getFont("Lato Medium", false, lbSpam.getFont().size));
lbSpam.setForeColor(0x215968);

// Done this for all the Labels, let's start adding them. Note that we use cont2.add () precisely because we are going to add in the second Container. We must not forget to pass the location.
cont2.add(lbDraftValue, CENTER, TOP, PREFERRED, PREFERRED);
cont2.add(lbInboxValue, BEFORE - fmH * 18, TOP, PREFERRED, PREFERRED);
cont2.add(lbSpamValue, AFTER + fmH * 18, TOP, PREFERRED, PREFERRED, lbDraftValue);
cont2.add(lbInbox, CENTER_OF, AFTER, PREFERRED, PREFERRED, lbInboxValue);
cont2.add(lbDraft, CENTER_OF, AFTER, PREFERRED, PREFERRED, lbDraftValue);
cont2.add(lbSpam, CENTER_OF, AFTER, PREFERRED, PREFERRED, lbSpamValue);

// Here we create a Button and call a method called aplyColor, which is in the Images class. You can see the method at the end of the CardProfile topic. But basically, in this method you pass the image and what the image should have.
btSend = new Button(Images.aplyColor(new Image("images/send.png"), 0xffffff));
btSend.setBackColor(0xC10828);
btSend.imageHeightFactor = 50;
// Let's repeat the process also listen to the buttons btAttach and btOthers
btAttach = new Button(Images.aplyColor(new Image("images/attach.png"), 0xFFFFFF));
btAttach.setBackColor(0xC10828);
btAttach.imageHeightFactor = 50;
btOthers = new Button(Images.aplyColor(new Image("images/settings.png"), 0xFFFFFF));
btOthers.setBackColor(0xC10828);
btOthers.imageHeightFactor = 50;

// And now let's add the buttons btAttach, btSend and btOthers as Container
add(
new Container() {
@Override
public void initUI() {
add(btAttach, CENTER, CENTER, DP + 80, DP + 40);
add(
new Container() {
@Override
public void initUI() {
add(btSend, CENTER, CENTER, DP + 80, DP + 40);
}
},
LEFT,
TOP,
FIT,
FILL);
add(
new Container() {
@Override
public void initUI() {
add(btOthers, CENTER, CENTER, DP + 80, DP + 40);
}
},
AFTER,
TOP,
FILL,
FILL,
btAttach);
}
},
LEFT,
AFTER,
FILL,
FILL);
} catch (ImageException | IOException e) {
e.printStackTrace();
}
}

The exemple above will show something like this image.







Copied!