What Is A Theme, What Is A Style & What Is a Component?

Every visual element within Codename One is a Component, the button on the screen is a Component and so is the Form in which it’s placed. This is all represented within the Component, which is probably the most central class in Codename One.

Every component has 4 standard style objects associated with it: Selected, Unselected, Disabled & Pressed.

If you wish to set a value to all component states you can use getAllStyles() which implicitly sets all the different styles. Notice that you must use it for write operations (set) and never use it for read operations (get).

Only one style is applicable at any given time and it can be queried via the getStyle() method. A style contains the colors, fonts, border and spacing information relating to how the component is presented to the user.

You should not use getStyle() in normal execution but instead use getUnselectedStyle(), getSelectedStyle(), getPressedStyle() & getDisabledStyle(). The reasoning is simple, getStyle() might return any one of those 4 depending on component state and you might not get the result you want. You should only use`getStyle()` when painting the component (e.g. in the paint callback method) to query information and not to set information.

A theme allows the designer to define the styles externally via a set of UIID’s (User Interface ID’s), the themes are created via the Codename One Designer tool and allow developers to separate the look of the component from the application logic.

Native Theme

By default Codename One applications are created with a theme that derives from the builtin OS native theme. You can add additional themes into the resource file by pressing the Add A New Theme button. You can also create multiple themes and ship them with your app or download them dynamically.

You can create a theme from scratch or customize one of the Codename one themes to any look you desire.

To preview the look of your theme in the various platforms use the Native Theme menu option in the designer.
The native theme menu option
Figure 1. The native theme menu option

You can easily create deep customizations that span across all themes by adding a UIID or changing an existing UIID. E.g. going back to our original hello world application the "GetStarted" UIID is defined within the designer as:

  • A green background

  • White forground

  • A thin medium sized font

  • Center aligned text

  • A small amount of spacing between the text and the edges

To achieve the colors we define them in the color tab.

We define the transparency to 255 which means the background will be a solid green color. This is important since the native OS’s might vary with the default value for background transparency so this should be defined explicitly.
The Color tab for the get started button theme settings
Figure 2. The Color tab for the get started button theme settings

The alignment of the text is pretty simple, notice that the alignment style attribute applies to text and doesn’t apply to other elements. To align other elements we use layout manager logic.

The alignment tab for the get started button theme settings
Figure 3. The alignment tab for the get started button theme settings

Padding can be expressed in pixels, millimeters (approximate) or percentages of the screen size.

We recommend using millimeters for all measurements to keep the code portable for various device DPI’s.
The padding tab for the get started button theme settings
Figure 4. The padding tab for the get started button theme settings

The font uses native OS light font but has a fallback for older OS’s that don’t support truetype fonts. The "True Type" font will be applicable for most modern OS’s. In the case of the "native:" fonts Android devices will use Roboto whereas iOS devices will use Helvetica Neue. You can supply your own TTF and work with that.

Since Codename One cannot legally ship Helvetica Neue fonts the simulator will fallback to Roboto on PC’s.
At the time of this writing the desktop/simulator version of the Roboto font doesn’t support many common character sets (languages). This will have no effect on an Android device where thenative font works properly.
The font tab for the get started button theme settings
Figure 5. The font tab for the get started button theme settings

Component/Container Hierarchy

Codename One Simplified Component Hierarchy
Figure 6. Codename One Simplified Component Hierarchy

The component class is the basis of all UI widgets in Codename One, to arrange multiple components together we use the Container class which itself “IS A” Component subclass. The Container is a Component that contains Components effectively allowing us to nest Containers infinitely to build any type of visual hierarchy we want by nesting Containers.

Component UML
Figure 7. Component UML

Layout Managers

Layout managers are installed on the Container class and effectively position the Components within the given container. The Layout class is abstract and allows users to create their own layout managers, however Codename One ships with multiple layout managers allowing for the creation of many layout types.

The layout managers are designed to allow developers to build user interfaces that seamlessly adapt to all resolutions and thus don’t state the component size/position but rather the intended layout behavior.

To install a layout manager one does something like this:

Container c = new Container(new BoxLayout(BoxLayout.X_AXIS));
c.addComponent(new Button("1"));
c.addComponent(new Button("2"));
c.addComponent(new Button("3"));

This would produce 3 buttons, one next to the other horizontally.

This can also be expressed using a shorter syntax since the add method returns a container:

Container c = new Container(new BoxLayout(BoxLayout.X_AXIS)).
    add(new Button("1")).
    add(new Button("2")).
    add(new Button("3"));
The add method can also accept an Image or a String. This will effectively wrap such data in a label so add("abc") would be equivalent to add(new Label("abc")).

There is an even shorter version since most layout managers have helper methods to facilitate smaller code sizes e.g. BoxLayout has encloseX(Component…​) that can be used as such:

Container c = BoxLayout.encloseX(new Button("1"),
                    new Button("2"), new Button("3"));

Constraint Based Layout Managers

There are two major types of layout managers:
Constraint based & regular. The regular layout managers like the box layout are just installed on the container and “do their job”. The constraint based layout managers associate a value with a Component sometimes explicitly and sometimes implicitly. Codename One ships with 6 such layouts BorderLayout, LayeredLayout, TableLayout, GridBagLayout, GroupLayout & MigLayout.

LayeredLayout can act as a regular layout or a constraint-based layout. If used as a regular layout, it automatically arranges child components on top of each other in layered. You can optionally provide constraints that specify insets on each child, and links between children.

A constraint layout CAN accept a value when adding the component to indicate its position. Notice that some layout manager require such a value (e.g. BorderLayout will throw an exception if a constraint is missing) whereas other constraint based layout managers will fallback to a sensible default (e.g. TableLayout).

You can use a constraint based layout like BorderLayout using syntax like this:

Container c = new Container(new BorderLayout());
c.addComponent(BorderLayout.CENTER, new Button("1"));
c.addComponent(BorderLayout.NORTH, new Button("2"));
c.addComponent(BorderLayout.SOUTH, new Button("3"));

This will stretch button 1 across the center of the container and buttons 2-3 will be stretched horizontally at the top and bottom of the container.

The order to adding doesn’t mean much for most constraint based layouts involved.

Like the above sample code this too can be written using terse syntax e.g.:

Container c = new Container(new BorderLayout()).
        add(BorderLayout.CENTER, new Button("1")).
        add(BorderLayout.NORTH, new Button("2")).
        add(BorderLayout.SOUTH, new Button("3"));

This can also be written with a helper method from the layout e.g.

Container c = BorderLayout.center(new Button("1")).
        add(BorderLayout.NORTH, new Button("2")).
        add(BorderLayout.SOUTH, new Button("3"));

Understanding Preferred Size

The Component class contains many useful methods, one of the most important ones is calcPreferredSize() which is invoked to recalculate the size a component “wants” when something changes

By default Codename One invokes the getPreferredSize() method and not calcPreferredSize() directly.
getPreferredSize() invokes calcPreferredSize() & caches the value.

The preferred size is decided by the component based on many constraints such as the font size, border sizes, padding etc.

When a layout manager positions & sizes the component, it MIGHT take the preferred size into account. Notice that it MIGHT ignore it entirely!

E.g. FlowLayout always gives components their exact preferred size, yet BorderLayout resizes the center component by default (and the other components on one of their axis).

You can define a group of components to have the same preferred width or height by using the setSameWidth & setSameHeight methods:

Component.setSameWidth(cmp1, cmp2, cmp3, cmp4);
Component.setSameHeight(cmp5, cmp6, cmp7);
Setting The Preferred Size

Codename One has a setPreferredSize method that allows developers to explicitly request the size of the component. However, this caused quite a lot of problems since the preferred size should change with device orientation or similar operations. The API also triggered frequent inadvertent hardcoding of UI values. As a result the method was deprecated.

We recommend developers use setSameWidth, setSameHeight when sizing alignment is needed. setHidden when hiding is needed. As a last resort we recommend overriding calcPreferredSize.

Flow Layout

Flow Layout
Figure 8. Flow Layout

Flow layout can be used to just let the components “flow” horizontally and break a line when reaching the edge of the container. It is the default layout manager for containers, but because it is so flexible it is often problematic as it can cause the preferred size of the Container to provide false/misleading information, triggering endless layout reflows.

Form hi = new Form("Flow Layout", new FlowLayout());
hi.add(new Label("First")).
    add(new Label("Second")).
    add(new Label("Third")).
    add(new Label("Fourth")).
    add(new Label("Fifth"));
hi.show();

Flow layout also supports terse syntax shorthand such as:

Container flowLayout = FlowLayout.encloseIn(
        new Label("First"),
        new Label("Second"),
        new Label("Third"),
        new Label("Fourth"),
        new Label("Fifth")));

Flow layout can be aligned to the left (the default), to the center, or to the right. It can also be vertically aligned to the top (the default), middle (center), or bottom.

Flow layout aligned to the center
Figure 9. Flow layout aligned to the center
Flow layout aligned to the right
Figure 10. Flow layout aligned to the right
Flow layout aligned to the center horizontally & the middle vertically
Figure 11. Flow layout aligned to the center horizontally & the middle vertically

Components within the flow layout get their natural preferred size by default and are not stretched in any axis.

The natural sizing behavior is often used to prevent other layout managers from stretching components. E.g. if we have a border layout element in the south and we want it to keep its natural size instead of adding the element to the south directly we can wrap it using parent.add(BorderLayout.SOUTH, FlowLayout.encloseCenter(dontGrowThisComponent)).

Box Layout

box-layout-x-no-grow

BoxLayout places elements in a row (X_AXIS) or column (Y_AXIS) according to box orientation. Box is a very simple and predictable layout that serves as the "workhorse" of component lists in Codename One.

You can create a box layout Y using something like this:

Form hi = new Form("Box Y Layout", new BoxLayout(BoxLayout.Y_AXIS));
hi.add(new Label("First")).
    add(new Label("Second")).
    add(new Label("Third")).
    add(new Label("Fourth")).
    add(new Label("Fifth"));

Which results in this

BoxLayout Y
Figure 12. BoxLayout Y

Box layout also supports a shorter terse notation which we use here to demonstrate the X axis box.

Container box = BoxLayout.encloseX(new Label("First"),
        new Label("Second"),
        new Label("Third"),
        new Label("Fourth"),
        new Label("Fifth")));
BoxLayout X
Figure 13. BoxLayout X

The box layout keeps the preferred size of its destination orientation and scales elements on the other axis. Specifically X_AXIS will keep the preferred width of the component while growing all the components vertically to match in size. Its Y_AXIS counterpart keeps the preferred height while growing the components horizontally.

This behavior is very useful since it allows elements to align as they would all have the same size.

In some cases the growing behavior in the X axis is undesired, for these cases we can use the X_AXIS_NO_GROW variant.

BoxLayout X_AXIS_NO_GROW
Figure 14. BoxLayout X_AXIS_NO_GROW
Comparing FlowLayout & BoxLayout - There are quite a few differences between FlowLayout and BoxLayout. When it doesn’t matter to you we recommend BoxLayout as it acts more consistently in all situations & is far simpler. Another advantage of BoxLayout is the fact that it grows and thus aligns nicely.

Border Layout

Border Layout
Figure 15. Border Layout

Border layout is quite unique, it’s a constraint-based layout that can place up to 5 components in one of the 5 positions: NORTH, SOUTH, EAST, WEST or CENTER.

Form hi = new Form("Border Layout", new BorderLayout());
hi.add(BorderLayout.CENTER, new Label("Center")).
    add(BorderLayout.SOUTH, new Label("South")).
    add(BorderLayout.NORTH, new Label("North")).
    add(BorderLayout.EAST, new Label("East")).
    add(BorderLayout.WEST, new Label("West"));
hi.show();

The layout always stretches the NORTH/SOUTH components on the X-axis to completely fill the container and the EAST/WEST components on the Y-axis. The center component is stretched to fill the remaining area by default. However, the setCenterBehavior allows us to manipulate the behavior of the center component so it is placed in the center without stretching.

E.g.:

Form hi = new Form("Border Layout", new BorderLayout());
((BorderLayout)hi.getLayout()).setCenterBehavior(BorderLayout.CENTER_BEHAVIOR_CENTER);
hi.add(BorderLayout.CENTER, new Label("Center")).
    add(BorderLayout.SOUTH, new Label("South")).
    add(BorderLayout.NORTH, new Label("North")).
    add(BorderLayout.EAST, new Label("East")).
    add(BorderLayout.WEST, new Label("West"));
hi.show();

Results in:

Border Layout with CENTER_BEHAVIOR_CENTER
Figure 16. Border Layout with CENTER_BEHAVIOR_CENTER
Because of its scaling behavior scrolling a border layout makes no sense. However it is a common mistake to apply a border layout to a scrollable container or trying to make a border layout scrollable. That is why Container explicitly blocks scrolling on a border layout.

In the case of RTL [1] the EAST and WEST values are implicitly reversed as shown in this image:

Border Layout in RTL mode
Figure 17. Border Layout in RTL mode
The preferred size of the center component doesn’t matter in border layout but the preferred size of the sides is. E.g. If you place an very large component in the SOUTH it will take up the entire screen and won’t leave room for anything.

Grid Layout

GridLayout accepts a predefined grid (rows/columns) and grants all components within it an equal size based on the dimensions of the largest component.

The main use case for this layout is a grid of icons e.g. like one would see in the iPhone home screen.

If the number of rows * columns is smaller than the number of components added a new row is implicitly added to the grid. However, if the number of components is smaller than available cells (won’t fill the last row) blank spaces will be left in place.

In this example we can see that a 2x2 grid is used to add 5 elements, this results in an additional row that’s implicitly added turning the grid to a 3x2 grid implicitly and leaving one blank cell.

Form hi = new Form("Grid Layout 2x2", new GridLayout(2, 2));
hi.add(new Label("First")).
    add(new Label("Second")).
    add(new Label("Third")).
    add(new Label("Fourth")).
    add(new Label("Fifth"));
Grid Layout 2x2
Figure 18. Grid Layout 2x2

When we use a 2x4 size ratio we would see elements getting cropped as we do here. The grid layout uses the grid size first and doesn’t pay too much attention to the preferred size of the components it holds.

Grid Layout 2x4
Figure 19. Grid Layout 2x4

Grid also has an autoFit attribute that can be used to automatically calculate the column count based on available space and preferred width. This is really useful for working with UI’s where the device orientation might change.

There is also a terse syntax for working with a grid that has two versions, one that uses the "auto fit" option and another that accepts the column names. Heres a sample of the terse syntax coupled with the auto fit screenshots of the same code in two orientations:

GridLayout.encloseIn(new Label("First"),
    new Label("Second"),
    new Label("Third"),
    new Label("Fourth"),
    new Label("Fifth")));
Grid Layout autofit portrait
Figure 20. Grid Layout autofit portrait
Grid Layout autofit landscape
Figure 21. Grid Layout autofit landscape

Table Layout

The TableLayout is a very elaborate constraint based layout manager that can arrange elements in rows/columns while defining constraints to control complex behavior such as spanning, alignment/weight etc.

The table layout is in the com.codename1.ui.table package and not in the layouts package.
This is due to the fact that TableLayout was originally designed for the Table class.

Despite being constraint based the table layout isn’t strict about constraints and will implicitly add a constraint when one is missing.

Unlike grid layout table layout won’t implicitly add a row if the row/column count is incorrect
Form hi = new Form("Table Layout 2x2", new TableLayout(2, 2));
hi.add(new Label("First")).
    add(new Label("Second")).
    add(new Label("Third")).
    add(new Label("Fourth")).
    add(new Label("Fifth"));
hi.show();
2x2 TableLayout with 5 elements
Figure 22. 2x2 TableLayout with 5 elements, notice that the last element is missing

Table layout supports the ability to grow the last column which can be enabled using the setGrowHorizontally method. You can also use a shortened terse syntax to construct a table layout however since the table layout is a constraint based layout you won’t be able to utilize its full power with this syntax.

The default usage of the encloseIn below uses the setGrowHorizontally flag.

Container tl = TableLayout.encloseIn(2, new Label("First"),
                new Label("Second"),
                new Label("Third"),
                new Label("Fourth"),
                new Label("Fifth")));
TableLayout.encloseIn() with default behavior of growing the last column
Figure 23. TableLayout.encloseIn() with default behavior of growing the last column
The Full Potential

Table layout is a beast, to truly appreciate it we need to use the constraint syntax which allows us to span, align and set width/height for the rows & columns.

Table layout works with a Constraint instance that can communicate our intentions into the layout manager. Such constraints can include more than one attribute e.g. span and height.

Table layout constraints can’t be reused for more than one component.

The constraint class supports the following attributes

Table 1. Constraint properties

column

The column for the table cell. This defaults to -1 which will just place the component in the next available cell

row

Similar to column, defaults to -1 as well

width

The column width in percentages, -1 will use the preferred size. -2 for width will take up the rest of the available space

height

Similar to width but doesn’t support the -2 value

spanHorizontal

The cells that should be occupied horizontally defaults to 1 and can’t exceed the column count - current offset.

spanVertical

Similar to spanHorizontal with the same limitations

horizontalAlign

The horizontal alignment of the content within the cell, defaults to the special case -1 value to take up all the cell space can be either -1, Component.LEFT, Component.RIGHT or Component.CENTER

verticalAlign

Similar to horizontalAlign can be one of -1, Component.TOP, Component.BOTTOM or Component.CENTER

You only need to set width/height to one cell in a column/row.

The table layout constraint sample tries to demonstrate some of the unique things you can do with constraints.

Due to the complexity of the code below we annotate lines with numbers and follow up on individual lines.
TableLayout tl = new TableLayout(2, 3); (1)
Form hi = new Form("Table Layout Cons", tl);
hi.setScrollable(false); (2)
hi.add(tl.createConstraint(). (3)
            widthPercentage(20),
                new Label("AAA")).

        add(tl.createConstraint(). (4)
            horizontalSpan(2).
            heightPercentage(80).
            verticalAlign(Component.CENTER).
            horizontalAlign(Component.CENTER),
                new Label("Span H")).

        add(new Label("BBB")).

        add(tl.createConstraint().
            widthPercentage(60).
            heightPercentage(20),
                new Label("CCC")).

        add(tl.createConstraint().
            widthPercentage(20),
                new Label("DDD"));
1 We need the table layout instance to create constraints. A constraint must be created for every component and must be used with the same layout as the parent container.
2 This is rather important. To get the look in the screenshot we need to turn scrolling off so the height constraint doesn’t take up available height. Otherwise it will miscalculate available height due to scrolling. You can scroll a table layout but sizing will be different.
3 We create the constraint and instantly apply width to it. This is a shorthand syntax for the code block below
4 We can chain constraint creation using a call like this so multiple constraints apply to a single cell. Notice that we don’t span and set width on the same axis (horizontal span + width), doing something like that would create confusing behavior.

Here is the full code mentioned in item 3:

TableLayout.Constraint cn = tl.createConstraint();
cn.setWidthPercentage(20);
hi.add(cn, new Label("AAA")).
TableLayout constraints can be used to create very elaborate UI's
Figure 24. TableLayout constraints can be used to create very elaborate UI’s

Layered Layout

When used without constraints, the LayeredLayout places the components in order one on top of the other and sizes them all to the size of the largest component. This is useful when trying to create an overlay on top of an existing component. E.g. an “x” button to allow removing the component.

The X on this button was placed there using the layered layout code below
Figure 25. The X on this button was placed there using the layered layout code below

The code to generate this UI is slightly complex and contains very few relevant pieces. The only truly relevant piece is this block:

hi.add(LayeredLayout.encloseIn(settingsLabel,
        FlowLayout.encloseRight(close)));

We are doing three distinct things here:

  1. We are adding a layered layout to the form.

  2. We are creating a layered layout and placing two components within. This would be the equivalent of just creating a LayeredLayout Container and invoking add twice.

  3. We use FlowLayout to position the X close button in the right position.

When used without constraints, the layered layout sizes all components to the exact same size one on top of the other. It usually requires that we use another container within; in order to position the components correctly.

This is the full source of the example for completeness:

Form hi = new Form("Layered Layout");
int w = Math.min(Display.getInstance().getDisplayWidth(), Display.getInstance().getDisplayHeight());
Button settingsLabel = new Button("");
Style settingsStyle = settingsLabel.getAllStyles();
settingsStyle.setFgColor(0xff);
settingsStyle.setBorder(null);
settingsStyle.setBgColor(0xff00);
settingsStyle.setBgTransparency(255);
settingsStyle.setFont(settingsLabel.getUnselectedStyle().getFont().derive(w / 3, Font.STYLE_PLAIN));
FontImage.setMaterialIcon(settingsLabel, FontImage.MATERIAL_SETTINGS);

Button close = new Button("");
close.setUIID("Container");
close.getAllStyles().setFgColor(0xff0000);
FontImage.setMaterialIcon(close, FontImage.MATERIAL_CLOSE);
hi.add(LayeredLayout.encloseIn(settingsLabel,
        FlowLayout.encloseRight(close)));

Forms have a built in layered layout that you can access via getLayeredPane(), this allows you to overlay elements on top of the content pane.

The layered pane is used internally by components such as InteractionDialog, AutoComplete etc.

Codename One also includes a GlassPane that resides on top of the layered pane. Its useful if you just want to "draw" on top of elements but is harder to use than layered pane.
Insets and Reference Components

As of Codename One 3.7, LayeredLayout supports insets for its children. This effectively allows you to position child components precisely where you want them, relative to their container or siblings. This functionality forms the under-pinnings of the GUI Builder’s Auto-Layout mode.

As an example, suppose you wanted to position a button in the lower right corner of its container. This can be achieved with LayeredLayout as follows:

Container cnt = new Container(new LayeredLayout());
Button btn = new Button("Submit");
LayeredLayout ll = (LayeredLayout)cnt.getLayout();
cnt.add(btn);
ll.setInsets(btn, "auto 0 0 auto");

The result is:

Button positioned in bottom right using insets

The only thing new here is this line:

ll.setInsets(btn, "auto 0 0 auto");

This is called after btn has already been added to the container. It says that we want its insets to be "auto" on the top and left, and 0 on the right and bottom. This insets string follows the CSS notation of top right bottom left (i.e. start on top and go clockwise), and the values of each inset may be provided in pixels (px), millimetres (mm), percent (%), or the special "auto" value. Like CSS, you can also specify the insets using a 1, 2, or 3 values. E.g.

  1. "1mm" - Sets 1mm insets on all sides.

  2. "1mm 2mm" - Sets 1mm insets on top and bottom; 2mm on left and right.

  3. "1mm 10% 2mm" - Sets 1mm on top, 10% on left and right, and 2mm on bottom.

  4. "1mm 2mm 1px 50%" - Sets 1mm on top, 2mm on right, 1px on bottom, and 50% on left.

auto Insets

The special "auto" inset indicates that it is a flexible inset. If all insets are set to "auto", then the component will be centered both horizontally and vertically inside its "bounding box".

The "inset bounding box" is the containing box from which a component’s insets are measured. If the component’s insets are not linked to any other components, then its inset bounding box will be the inner bounds (i.e. taking padding into account) of the component’s parent container.

If one inset is fixed (i.e. defined in px, mm, or %), and the opposite inset is "auto", then the "auto" inset will simply allow the component to be its preferred size. So if you want to position a component to be centered vertically, and 5mm from the left edge, you could do:

ll.setInsets(btn, "auto auto auto 5mm");

Resulting in:

Button vertically centered 5mm from left edge
Figure 26. Button vertically centered 5mm from left edge

Move it to the right edge with:

ll.setInsets(btn, "auto 5mm auto auto");
% Insets

Percent (%) insets are calculated with respect to the inset bounding box. A 50% inset is measured as 50% of the length of the bounding box on the inset’s axis. E.g. A 50% inset on top would be 50% of the height of the inset bounding box. A 50% inset on the right would be 50% of the width of the inset bounding box.

Insets, Margin, and Padding

A component’s position in a layered layout is determined as follows: (Assume that cmp is the component that we are positioning, and cnt is the container (In pseudo-code):

x = cnt.paddingLeft + cmp.calculatedInsetLeft + cmp.marginLeft
y = cnt.paddingTop + cmp.calculatedInsetTop + cmp.marginTop
w = cnt.width - cnt.verticalScroll.width - cnt.paddingRight - cmp.calculatedInsetRight - cmp.marginRight - x
h = cnt.height - cnt.horizontalScroll.height - cnt.paddingBottom - cmp.calculatedInsetBottom - cmp.marginBottom - y
The calculatedInsetXXX values here will be the same as the corresponding provided inset if the inset has no reference component. If it does have a reference component, then the calculated inset will depend on the position of the reference component.

If no inset is specified, then it is assumed to be 0. This ensures compatibility with designs that were created before layered layout supported insets.

Component References: Linking Components together

If all you need to do is position a component relative to its parent container’s bounds, then mere insets provide you with sufficient vocabulary to achieve this. But most UIs are more complex than this and require another concept: reference components. In many cases you will want to position a component relative to another child of the same container. This is also supported.

For example, suppose I want to place a text field in the center of the form (both horizontally and vertically), and have a button placed beside it to the right. Positioning the text field is trivial (setInset(textField, "auto")), but there is no inset that we can provide that would position the button to the right of the text field. To accomplish our goal, we need to set the text field as a reference component of the button’s left inset - so that the button’s left inset is "linked" to the text field. Here is the syntax:

Container cnt = new Container(new LayeredLayout());
LayeredLayout ll = (LayeredLayout)cnt.getLayout();
Button btn = new Button("Submit");
TextField tf = new TextField();
cnt.add(tf).add(btn);
ll.setInsets(tf, "auto")
  .setInsets(btn, "auto auto auto 0")
  .setReferenceComponentLeft(btn, tf, 1f);

This would result in:

Button's left inset linked to text field
Figure 27. Button’s left inset linked to text field

The two active lines here are the last two:

  .setInsets(btn, "auto auto auto 0") (1)
  .setReferenceComponentLeft(btn, tf, 1f); (2)
1 Sets the left inset on btn to 0.
2 Links btn’s left inset to `tf so that it is measured from the text field. The third parameter (1.0) is the reference position. This will generally either be 0 (meaning the reference point is the left edge of the text field), or 1 (meaning the reference point is the right edge of the text field). In this case we set a reference position of 1.0 because we want the button to be aligned to the text field’s right edge.
The reference position is defined as the distance, expressed as a fraction of the reference component’s length on the inset’s axis, between the reference component’s leading (outer) edge and the point from which the inset is measured. A reference position of 0 means that the inset is measured from the leading edge of the reference component. A value of 1.0 means that the inset is measured from the trailing edge of the reference component. A value of 0.5 means that the inset is measured from the center of the reference component. Etc…​ Any floating point value can be used. The designer currently only makes use of 0 and 1.

The definition above may make reference components and reference position seem more complex than it is. Some examples:

  1. For a top inset:

    1. referencePosition == 0 ⇒ the inset is measured from the top edge of the reference component.

    2. referencePosition == 1 ⇒ the inset is measured from the bottom edge of the reference component.

  2. For a bottom inset:

    1. referencePosition == 0 ⇒ the inset is measured from the bottom edge of the reference component.

    2. referencePosition == 1 ⇒ the inset is measured from the top edge of the reference component.

  3. For a left inset:

    1. referencePosition == 0 ⇒ the inset is measured from the left edge of the reference component.

    2. referencePosition == 1 ⇒ the inset is measured from the right edge of the reference component.

  4. For a right inset:

    1. referencePosition == 0 ⇒ the inset is measured from the right edge of the reference component.

    2. referencePosition == 1 ⇒ the inset is measured from the left edge of the reference component.

GridBag Layout

GridBagLayout was introduced to simplify the process of porting existing Swing/AWT code with a more familiar API. The API for this layout is problematic as it was designed for AWT/Swing where styles were unavailable. As a result it has its own insets API instead of using elements such as padding/margin.

Our recommendation is to use Table which is just as powerful but has better Codename One integration.

To demonstrate grid bag layout we ported the sample from the Java tutorial to Codename One.

Button button;
hi.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
//natural height, maximum width
c.fill = GridBagConstraints.HORIZONTAL;


button = new Button("Button 1");
c.weightx = 0.5;
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.gridy = 0;
hi.addComponent(c, button);

button = new Button("Button 2");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 1;
c.gridy = 0;
hi.addComponent(c, button);

button = new Button("Button 3");
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.gridx = 2;
c.gridy = 0;
hi.addComponent(c, button);

button = new Button("Long-Named Button 4");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 40;      //make this component tall
c.weightx = 0.0;
c.gridwidth = 3;
c.gridx = 0;
c.gridy = 1;
hi.addComponent(c, button);

button = new Button("5");
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 0;       //reset to default
c.weighty = 1.0;   //request any extra vertical space
c.anchor = GridBagConstraints.PAGE_END; //bottom of space
c.insets = new Insets(10,0,0,0);  //top padding
c.gridx = 1;       //aligned with button 2
c.gridwidth = 2;   //2 columns wide
c.gridy = 2;       //third row
hi.addComponent(c, button);

Notice that because of the way gridbag works we didn’t provide any terse syntax API for it although it should be possible.

GridbagLayout sample from the Java tutorial running on Codename One
Figure 28. GridbagLayout sample from the Java tutorial running on Codename One

Group Layout

GroupLayout is a layout that would be familiar to the users of the NetBeans GUI builder (Matisse). Its a layout manager that’s really hard to use for manual coding but is remarkably powerful for some really elaborate use cases.

It was originally added during the LWUIT days as part of an internal attempt to port Matisse to LWUIT. It is still useful to this day as developers copy and paste Matisse code into Codename One and produce very elaborate layouts with drag & drop.

Since the layout is based on an older version of group layout some things need to be adapted in the code or you should use the special "compatibility" library for Matisse to get better interaction. We also recommend tweeking Matisse to use import statements instead of full package names, that way if you use Label just changing the awt import to a Codename One import will make it use Label.

Unlike any other layout manager group layout adds the components into the container instead of the standard API. This works nicely for GUI builder code but as you can see from this sample it doesn’t make the code very readable:

Form hi = new Form("GroupLayout");

Label label1 = new Label();
Label label2 = new Label();
Label label3 = new Label();
Label label4 = new Label();
Label label5 = new Label();
Label label6 = new Label();
Label label7 = new Label();

label1.setText("label1");

label2.setText("label2");

label3.setText("label3");

label4.setText("label4");

label5.setText("label5");

label6.setText("label6");

label7.setText("label7");

GroupLayout layout = new GroupLayout(hi.getContentPane());
hi.setLayout(layout);
layout.setHorizontalGroup(
    layout.createParallelGroup(GroupLayout.LEADING)
    .add(layout.createSequentialGroup()
        .addContainerGap()
        .add(layout.createParallelGroup(GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(label1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(LayoutStyle.RELATED)
                .add(layout.createParallelGroup(GroupLayout.LEADING)
                    .add(label4, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .add(label3, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .add(label2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
            .add(label5, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
            .add(layout.createSequentialGroup()
                .add(label6, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(LayoutStyle.RELATED)
                .add(label7, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)))
        .addContainerGap(296, Short.MAX_VALUE))
);
layout.setVerticalGroup(
    layout.createParallelGroup(GroupLayout.LEADING)
    .add(layout.createSequentialGroup()
        .addContainerGap()
        .add(layout.createParallelGroup(GroupLayout.TRAILING)
            .add(label2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
            .add(label1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
        .addPreferredGap(LayoutStyle.RELATED)
        .add(label3, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(LayoutStyle.RELATED)
        .add(label4, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(LayoutStyle.RELATED)
        .add(label5, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(LayoutStyle.RELATED)
        .add(layout.createParallelGroup(GroupLayout.LEADING)
            .add(label6, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
            .add(label7, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
        .addContainerGap(150, Short.MAX_VALUE))
);
GroupLayout Matisse generated UI running in Codename One
Figure 29. GroupLayout Matisse generated UI running in Codename One

If you are porting newer Matisse code there are simple changes you can do:

  • Change addComponent to add

  • Change addGroup to add

  • Remove references to ComponentPlacement and reference LayoutStyle directly

Mig Layout

MigLayout is a popular cross platform layout manager that was ported to Codename One from Swing.

MiG is still considered experimental so proceed with caution!
The API was deprecated to serve as a warning of its experimental status.

The best reference for MiG would probably be its quick start guide (PDF link). As a reference we ported one of the samples from that PDF to Codename One:

Form hi = new Form("MigLayout", new MigLayout("fillx,insets 0"));

hi.add(new Label("First")).
    add("span 2 2", new Label("Second")).  // The component will span 2x2 cells.
    add("wrap", new Label("Third")).      // Wrap to next row
    add(new Label("Forth")).
    add("wrap", new Label("Fifth")).    // Note that it "jumps over" the occupied cells.
    add(new Label("Sixth")).
    add(new Label("Seventh"));
hi.show();
MiG layout sample ported to Codename One
Figure 30. MiG layout sample ported to Codename One

It should be reasonably easy to port MiG code but you should notice the following:

  • MiG handles a lot of the spacing/padding/margin issues that are missing in Swing/AWT. With Codename One styles we have the padding & margin which are probably a better way to do a lot of the things that MiG does

  • The add method in Codename One can be changed as shown in the sample above.

  • The constraint argument for Coedname One add calls appears before the Component instance.

GUI Builder

The GUI builder is still in heavy development at this time, it shouldn’t be confused with the old GUI builder that is a part of the Codename One designer tool

The GUI builder allows us to arrange components visually within a UI using drag & drop, property sheets etc. With the GUI builder we can create elaborate, rich UI’s without writing the layout code.

Why two GUI Builders?

The original old GUI builder has its roots in our work at Sun Microsystems, it was developed directly into the designer tool and stores it’s data as part of the resource file. When creating an application for the old GUI builder you must define it as a "visual application" which will make it use the old GUI builder.

The roots of this GUI builder are pretty old. When we initially built it we still had to support feature phones with 2mb of RAM and the iPad wasn’t announced yet. Due to that we picked an architecture that made sense for those phones with a greater focus on navigation and resource usage. Newer mobile applications are rivaling desktop applications in complexity and in those situations the old GUI builder doesn’t make as much sense

The old GUI builder is in the designer tool, it’s a Swing application that includes the theme design etc.
It generates a Statemachine class that contains all the main user GUI interaction code.

The new GUI builder is a standalone application that you launch from the right click menu by selecting a form as explained below. Here are screenshots of both to help you differentiate:

The old GUI builder
Figure 31. The old GUI builder
The new GUI builder
Figure 32. The same UI in the new GUI builder

As of version 3.7, the new GUI Builder also supports an auto layout mode which allows you to freely position and resize components on a canvas. This mode is now the default for new GUI forms, and it always uses LayeredLayout as the root layout manager.

The new GUI builder auto layout mode
Figure 33. The new GUI builder in auto-layout mode

Hello World

Creating a hello world app in the new GUI builder is actually pretty trivial, you need to start with a regular handcoded application. Not a GUI builder application as it refers to the old GUI builder!

Creating a new hello world is similar for all IDE’s and is covered in all the getting started tutorials for the various IDE’s specifically in NetBeans, IntelliJ & Eclipse.

The new GUI builder requires Java 8. This means the IDE itself needs to run on top of Java 8!

Following are the instructions for creating a form and launching the GUI builder. While they are similar there are minor IDE differences. Usage of the GUI builder is identical in all IDE’s as the GUI builder is a separate application.

NetBeans

In NetBeans you need to follow these 4 steps:

Right click the package select New -> Other
Figure 34. Right click the package select NewOther
In the Codename One section select the GUI builder form
Figure 35. In the Codename One section select the GUI builder form
Type in the name of the form and click finish
Figure 36. Type in the name of the form and click finish, you can change the type to be a Container or Dialog
Launch the GUI builder thru the right click menu on the newly created file
Figure 37. Launch the GUI builder thru the right click menu on the newly created file
IntelliJ/IDEA

In IntelliJ you need to follow these 3 steps:

Right click the package select New -> Codename One Form (or Dialog/Container)
Figure 38. Right click the package select NewCodename One Form (or Dialog/Container)
Type in a name for the new form
Figure 39. Type in a name for the new form
Launch the GUI builder thru the right click menu on the newly created file
Figure 40. Launch the GUI builder thru the right click menu on the newly created file
Eclipse

In Eclipse you need to follow these 4 steps:

Right click the package select New -> Other
Figure 41. Right click the package select NewOther
In the Codename One section select the GUI builder option
Figure 42. In the Codename One section select the GUI builder option
Type in the name of the form and click finish
Figure 43. Type in the name of the form and click finish, you can change the type to be a Container or Dialog
Launch the GUI builder thru the right click menu on the newly created file
Figure 44. Launch the GUI builder thru the right click menu on the newly created file
Basic Usage

Notice that the UI of the new GUIBuilder might change in various ways but the basic concepts should remain the same.

The GUI builder is controlled via it’s main toolbar, notice that your changes will only be applied when you click the Save button on the right:

The features of the main toolbar
Figure 45. The features of the main toolbar

The sidebar includes the functionality we will be working with most of the time:

The sidebar options
Figure 46. The sidebar options

We’ll start by selecting the Component Palette and dragging a button into the UI:

You can drag any component you want from the sidebar to the main UI
Figure 47. You can drag any component you want from the sidebar to the main UI

You can then re-arrange the order of the components but since they use the default FlowLayout you can’t position them anywhere you want. We’ll discuss arrangement and layout managers in the GUI builder below.

You should have a UI that looks like this when you select the button you placed, it shows the properties that you can modify and the events that you can bind:

Properties allow you to customize everything about a component
Figure 48. Properties allow you to customize everything about a component

You can edit any property by clicking it, this launches the appropriate UI. E.g. for image properties you will be presented with an image dialog that allows you to pick an image from the resource file:

You can edit properties such as the icon property by clicking it
Figure 49. You can edit properties such as the icon property by clicking it, this opens the image selection dialog
You can add an image to the resource file using the designer tool as covered in this video

For things like setting the text on the component we can use a convenient "long click" on the component to edit the text in place as such:

Use the long click to edit the text
Figure 50. Use the long click to edit the text "in place"
Events

When a component supports broadcasting events you can bind such events by selecting it, then selecting the events tab and clicking the button matching the event type

The events tab is listed below supported event types can be bound above
Figure 51. The events tab is listed below supported event types can be bound above

Once an event is bound the IDE will open to the event code e.g.:

public void onButton_1ActionEvent(com.codename1.ui.events.ActionEvent ev) {
}
Some IDE’s only generate the project source code after you explicitly build the project so if your code needs to access variables etc. try building first

Within the code you can access all the GUI components you defined with the gui_ prefix e.g. Button_1 from the UI is represented as:

private com.codename1.ui.Button gui_Button_1 = new com.codename1.ui.Button();
Layouts

In this section we won’t try to discuss layouts in depth as this is a deep and complex subject. You can read more about the properties of the various Codename One layouts in the developer guide.

In general layouts define the mathematical logic for component positions that we can then apply to the various resolutions supported by the devices. If we didn’t have layouts the UI wouldn’t fit on the multitude of devices where it should work. You can nest layouts by placing containers within the UI and giving any container a different layout manager, this allows you to construct very elaborate layouts.

You can pick a layout manager using this UI:

Layouts can be picked via the GUI builder UI
Figure 52. Layouts can be picked via the GUI builder UI

Most layouts support settings that allow you to configure their behavior, e.g. FlowLayout supports settings such as these that allow you to align the components within it to various locations:

FlowLayout settings
Figure 53. FlowLayout settings

BorderLayout & TableLayout support constraints that allow you to provide additional hints about the components within the layout:

Border layout constraints
Figure 54. Border layout constraints

Mixing these layouts in a hierarchy allows you to produce most UI’s.

E.g. one of the most powerful tricks in the new GUI builder is the multi selection mode:

Multi selection icon
Figure 55. Multi selection icon

When this mode is turned on the icon turns into a cancel icon to cancel that mode. When it’s turned on you can select multiple components and perform operations on all of them such as changing a property on multiple components or enclosing them in a container e.g.:

When we toggle on multi-select mode and select several components we can then enclose them in a Container
Figure 56. When we toggle on multi-select mode and select several components we can then enclose them in a Container
Underlying XML

Saving the project generates an XML file representing the UI into the res directory in the project, the GUI file is created in a matching hierarchy in the project under the res/guibuilder directory:

The java and GUI files in the hierarchy
Figure 57. The java and GUI files in the hierarchy
If you refactor (rename or move) the java file it’s connection with the GUI file will break. You need to move/rename both

You can edit the GUI file directly but changes won’t map into the GUI builder unless you reopen it. These files should be under version control as they are the main files that change. The GUI builder file for the button and label code looks like this:

<?xml version="1.0" encoding="UTF-8"?>

<component type="Form" layout="FlowLayout" flowLayoutFillRows="false" flowLayoutAlign="1"
flowLayoutValign="0"  title="My new title" name="MyForm">
  <component type="Button" text="Button" name="Button_1" actionEvent="true">
  </component>
  <component type="Label" text="Hi World" name="Label_1">
  </component>
</component>

This format is relatively simple and is roughly the same format used by the old GUI builder which makes the migration to the new GUI builder possible. This file triggers the following Java source file:

package com.mycompany.myapp;

/**
 * GUI builder created Form
 *
 * @author shai
 */
public class MyForm extends com.codename1.ui.Form {

    public MyForm() {
        this(com.codename1.ui.util.Resources.getGlobalResources());
    }

    public MyForm(com.codename1.ui.util.Resources resourceObjectInstance) {
        initGuiBuilderComponents(resourceObjectInstance);
    }

//-- DON'T EDIT BELOW THIS LINE!!!
    private com.codename1.ui.Label gui_Label_1 = new com.codename1.ui.Label();
    private com.codename1.ui.Button gui_Button_1 = new com.codename1.ui.Button();


// <editor-fold defaultstate="collapsed" desc="Generated Code">
    private void guiBuilderBindComponentListeners() {
        EventCallbackClass callback = new EventCallbackClass();
        gui_Button_1.addActionListener(callback);
    }

    class EventCallbackClass implements com.codename1.ui.events.ActionListener, com.codename1.ui.events.DataChangedListener {
        private com.codename1.ui.Component cmp;
        public EventCallbackClass(com.codename1.ui.Component cmp) {
            this.cmp = cmp;
        }

        public EventCallbackClass() {
        }

        public void actionPerformed(com.codename1.ui.events.ActionEvent ev) {
            com.codename1.ui.Component sourceComponent = ev.getComponent();
            if(sourceComponent.getParent().getLeadParent() != null) {
                sourceComponent = sourceComponent.getParent().getLeadParent();
            }

            if(sourceComponent == gui_Button_1) {
                onButton_1ActionEvent(ev);
            }
        }

        public void dataChanged(int type, int index) {
        }
    }
    private void initGuiBuilderComponents(com.codename1.ui.util.Resources resourceObjectInstance) {
        guiBuilderBindComponentListeners();
        setLayout(new com.codename1.ui.layouts.FlowLayout());
        setTitle("My new title");
        setName("MyForm");
        addComponent(gui_Label_1);
        addComponent(gui_Button_1);
        gui_Label_1.setText("Hi World");
        gui_Label_1.setName("Label_1");
        gui_Button_1.setText("Click Me");
        gui_Button_1.setName("Button_1");
    }// </editor-fold>

//-- DON'T EDIT ABOVE THIS LINE!!!
    public void onButton_1ActionEvent(com.codename1.ui.events.ActionEvent ev) {
    }

}
Don’t touch the code within the DON’T EDIT comments…​

The GUI builder uses the "magic comments" approach where code is generated into those areas to match the XML defined in the GUI builder. Various IDE’s generate that code at different times. Some will generate it when you run the app while others will generate it as you save the GUI in the builder.

You can write code freely within the class both by using the event mechanism, by writing code in the constructors or thru overriding functionality in the base class.

Auto-Layout Mode

As of version 3.7, new forms created with the new GUI Builder will use auto-layout mode. In this mode you can move and resize your components exactly as you see fit. You aren’t constrained to the positions dictated by the form’s layout manager.

Auto-Layout Mode is built upon the new inset support in LayeredLayout. All forms designed in auto-layout mode use LayeredLayout. Component positioning uses insets and reference components, not absolute positioning.

As an example, let’s drag a button onto a blank form and see what happens. The button will be "selected" initially after adding, it so you’ll see its outline, and resize handles for adjusting its size and position. You’ll also see four floating labels (above, below, to the left, and to the right) that show the corresponding side’s inset values and allow you to adjust them.

Selected component in designer allows you to freely drag it to a new position
Figure 58. A button selected on the canvas in auto-layout mode. You can drag it to reposition it, or resize it using the resize handles.

Press the mouse inside the bounds of the button and drag it around to reposition it. You will notice that the inset labels change to reflect the new inset values. If you drag the button close to the edge of the form, the corresponding inset value will change to millimetres. If you move farther away from the edge, it will change to percentage values.

The Inset Control

Let’s take a closer look at the inset control (the inset controls are the black buttons that appear to the top, bottom, left, and right of the selected component).

Inset control
Figure 59. The inset control allows you to change the inset size and units, toggle it between fixed and flexible, and link it to another component.

Each control has three sections:

  1. The inset value drop-down menu. This shows the current value of the inset (e.g. 0mm, 25%, auto, etc…​). If you click on this, it will open a menu that will allow you to change the units. If the inset is currently in millimetres, it will have options for pixels, and percent. If the inset is in percent, it will have options for pixels and millimetres. Etc.. It also includes a text field to enter a an inset value explicitly.

    Inset drop-down menu
  2. The "Link" Button Link button - If the inset is linked to a reference component, then this button will be highlighted "blue", and hovering over it will highlight the reference component in the UI so that you can clearly see which component it is linked to. Clicking on this button will open a dialog that will allow you to "break" this link. You can drag this button over any component in the form to "link".

  3. The "Lock" Button" Inset fixed button - This button allows you to toggle the inset between "flexible" (i.e. auto) and "fixed" (i.e. millimetres or percent).

Auto Snap

Notice the "auto-snap" checkbox that appears in the top-right corner of the designer.

Auto-snap checkbox

Auto-snap does exactly what it sounds like: It automatically snaps two components together when you drag them near each other. This is handy for linking components together without having to explicitly link them (using the "link" button). This feature is turned on by default. If auto-snap is turned off, you can still initiate a "snap" by holding down the ALT/Option key on your keyboard during the drag.

Smart Insets

Beside the "auto-snap" checkbox is another checkbox named "Smart Insets".

Smart insets checkbox

Smart Insets is an experimental feature at this point. It uses some heuristics during a drag to try to determine how the insets should be linked. Currently the heuristics are quite basic (it tries to link to the nearest neighbour component in most cases), but we will be working on improving this for future releases. This feature is turned off by default while it is still being refined. The goal is to improve this to the point where it always makes the correct link choices - at which time you will be able to use the designer without having any knowledge of insets or reference components. It will just work. In the current version, I generally work with auto-snap "on", and explicitly assign links myself using the "link" button. This gives me full control of my UI and how it will be resized. Once you get used to insets and how the links work, it becomes quite easy.

The Widget Control Pad
Widget control pad

When a component is selected, you should see a black floating panel appear in the lower right of the screen.

This is the widget control pad, and it provides an alternative view of the component’s links. It also provides a useful list of incoming links (i.e. components that "depend on" this component’s positioning). In some cases, you may want to disconnect incoming links so that you can drag the component without affecting the position of dependent components.

This control pad also includes game-pad-like controls (up, down, left, right), that allow you to "tab" the component to the next guide in that direction. Tab positions exist at component edges in the form. This is useful for aligning components with each other.

Keyboard Short-Cuts
  1. Arrow Keys - Use the up/down/left/right arrow keys to nudge the currently selected component a little bit at a time. This is a convenient way to move the component to a position that is more precise than can easily be achieved with a mouse drag.

  2. Arrow Keys + SHIFT - Hold down the SHIFT key while pressing an arrow key and it will "tab" the component to the next tab marker. The form has implicit tab markers at the edge of each component on the form.

  3. ALT/Option Key + Click or Drag - Holding down the option/alt key while clicking or dragging a component will resulting in "snapping" behaviour even if auto-snap is turned off.

Sub-Containers

In some cases, you may need to add sub-containers to your form to aid in grouping your components together. You can drag a container onto your form using the "Container" palette item (under "Core Components"). The default layout the subcontainer will be LayeredLayout so that you are able to position components within the sub-container with precision, just like on the root container.

You can also change the layout of subcontainers to another classical layout manager (e.g. grid layout, box layout, etc..) and drag components directly into it just as you did with the old designer. This is very useful if parts of your form lend themselves. As an example, let’s drag a container onto the canvas that uses BoxLayout Y. (You can find this under the "Containers" section of the component palette).

Drag the button (that was previously on the form) over that container, and you should see a drop-zone become highlighted.

Dropping container on child container with box layout y

You can drop the button directly there. You can As you drag more components into the sub-container, you’ll see them automatically laid out vertically.

Box Layout Y dropping 2nd child
The Canvas Resize Tool

When designing a UI with the new designer it is very important that you periodically test the form’s "resizing" behaviour so that you know how it will behave on different devices. Components may appear to be positioned correctly when the canvas is one size, but become out of whack when the container is resized. After nearly every manipulation you perform, it is good practice to drag the canvas resize tool (the button in the lower right corner of the designer) smaller and bigger so you can see how the positions are changed. If things grow out of whack, you may need to toggle an inset between fixed and auto, or add a link between some of the components so that the resizing behaviour matches your expectations.

Track Designer & GUI Builder Issues

Both of these tools have issues most of which resolve around their connection to the IDE. The reason for this is that they are external tools that aren’t a part of the IDE, this allows us to support all 3 IDE’s without too much of an effort but also creates some issues that are often hard to debug.

When you open either the designer or the GUI builder we install a JAR file within your system. This JAR file is located under the .codenameone directory in your home directory. E.g. on Linux/Mac it would be ~ but for Windows it can be under several hierarchies, see this.

Once you locate the home directory peak inside, you should see two files: designer_1.jar & guibuilder_1.jar.

Both will only exist if you opened the designer and GUI builder, also notice that the _1 part of the file name might be missing and that’s fine

Command Line

You can launch both tools from Command Line. These tools write errors to the system console and you would see errors if they occur. Notice that both tools need Java 8 to work…​ To launch the designer use:

java -jar designer_1.jar path-to-file.res

To launch the GUI builder use:

java -jar guibuilder_1.jar

If you see errors please look them over and let us know what the full set of errors is.

Problem: Designer Won’t Launch

This happens to some Eclipse users. The designer will launch from command line but not from Eclipse. Despite many attempts we failed to reproduce this.

Our current working theory is that Java home and the Java in the system path are incompatible maybe due to 64/32 bit modes or an older version of Java. Another theory is that a path with spaces or invalid characters is causing this issue.

If you are experiencing this issue please review your environment:

  • The bin directory of the JDK (important, the JDK not the JRE) must be first in the system path. Before anything else! Especially before Windows as some versions of the JDK stick Java into the system directory

  • JAVA_HOME must point at the JDK directory

  • You should have administrator privileges, I’m not sure if this is essential but please test this

  • Look in eclipse.ini and verify that the JDK listed there matches the JDK from the path

GUI Builder Issues

There are several reasons for this and we try to address them with newer releases. To understand how this works check out the .guiBuilder directory in your home directory. In this directory you should see a file called guibuilder.input which is responsible for picking the right file to edit. This is mine:

<?xml version="1.0" encoding="UTF-8"?>
<con name="GuiBuilderTutorial" formName="MyGuiForm"  file="file:/Users/shai/temp/GuiBuilderTutorial/res/guibuilder/com/mycompany/myapp/MyGuiForm.gui" javaFile="file:/Users/shai/temp/GuiBuilderTutorial/src/com/mycompany/myapp/MyGuiForm.java" resFile="file:/Users/shai/temp/GuiBuilderTutorial/src/theme.res" outputFile="file:/Users/shai/.guiBuilder/733a5319-ceeb-458c-abad-6e2a6a061e05.ouput" running="file:/Users/shai/.guiBuilder/733a5319-ceeb-458c-abad-6e2a6a061e05" />

The important attributes here are file and javaFile. The former represents the XML gui file and the latter represents the Java source file related to that. If the path is invalid the GUI builder won’t find the right files and won’t know what to do.

The content of the .gui file might also be important if the GUI builder suddently stops working for a specific file.

Static Global Context

The CN class provides a better approach for doing the things we do today in Display, NetworkManager, Storage, FileSystemStorage etc. with one class. It also adds common methods & constants from several other classes so Codename One code will feel more terse e.g. we can do:

import static com.codename1.ui.CN.*;
That’s optional, if you don’t like static imports you can just write CN. for every element

From that point on you can write code that looks like this:

callSerially(() -> runThisOnTheEDT());

Instead of:

Display.getInstance().callSerially(() -> runThisOnTheEDT());

The same applies for most network manager calls e.g.:

addToQueue(myConnectionRequest);

Some things were changed so we won’t have too many conflicts e.g. Log.p or Log.e would have been problematic so we now have:

log("my log message");
log(myException);

Instead of Display.getInstance().getCurrent() we now have getCurrentForm() since getCurrent() is too generic. But for most methods you should just be able to remove the NetworkManager or Display access and it should "just work".

I ported the Kitchen Sink to use this new convention, to see a sample of how this can cut down on code clutter check of this diff of my commit.

The motivation for this is three fold:

  • Terse code

  • Small performance gain

  • Cleaner API without some of the baggage in Display or NetworkManager

Some of our samples in this guide might rely on that static import being in place.


1. RTL = Right To Left or Bidi = bi-directional. A common term used for languages such as Hebrew or Arabic that are written from the right to left direction hence all the UI needs to be "reversed". Bidi denotes the fact that while the language is written from right to left, the numbers are still written in the other direction hence two directions…​