Extending LWUIT layouts on Series 40
This code example shows how to extend the LWUIT framework to create new UI layouts.
Article Metadata
Code Example
Tested with
Compatibility
Article
Contents |
Introduction
Lightweight UI Toolkit (LWUIT) is a UI framework and "widget" library for Java ME. It comes with a number of in-built Layouts, which allow you to organize components such as buttons, labels, checkbox, radiobuttons etc on the screen inside a container. The most common layouts include:
- BoxLayout - allows to organize the components in a linear way either along the X axis or the Y axis
- BorderLayout - allows to organize the components in 5 different locations North,South,Center,East,West
- GridLayout - allows to organize the components in a grid of cells.
- FlowLayout,TableLayout,etc
The default layouts are more than sufficient for most apps, but if you want to define your own cool and unique layout style, LWUIT allows you to extend the basic Layout class and implement your own organization of the components inside of the container.
This code example shows you how to create a new Layout called CircularLayout, which organizes its components in a circle around a central point. This sort of organization is almost impossible to achieve using the build-in layouts.
Implement the abstract classes
When extending the Layout class you need to implement the two abstract methods:
Both methods receive the parent Container parameter which they are associated with. The getPreferredSize() method should return the preffered size in pixels of Width x Height the required layout. The ayoutContainer() method does the actual layout of the components inside the parent Container (which basically means setting the components sizes and location (x,y) relative to the container location).
Source code for the layout
import com.sun.lwuit.Component;
import com.sun.lwuit.Container;
import com.sun.lwuit.geom.Dimension;
import com.sun.lwuit.layouts.Layout;
import com.sun.lwuit.plaf.Style;
/**
* @author ifrach shai
*/
public class CircularLayout extends Layout {
private int startAngel;
private int clockWise;
public CircularLayout()
{
this(270, true);
}
public CircularLayout(int startAngel, boolean clockWise)
{
this.startAngel = startAngel;
this.clockWise = clockWise ? -1 : 1;
}
/**
* returns the preffered size the layout needs in order to properly arrange the components
*/
public Dimension getPreferredSize(Container parent)
{
int components = parent.getComponentCount();
double largestDiameter = 0;
for (int iter = 0; iter < components; iter++)
{
Component current = parent.getComponentAt(iter);
Dimension d = current.getPreferredSize();
largestDiameter = Math.max(largestDiameter, Math.sqrt(d.getWidth() * d.getWidth() + d.getHeight()
* d.getHeight()));
}
double angelPart = 360f / components;
double otherAngel = (180 - angelPart) / 2;
int radius = (int) (largestDiameter * Math.sin(Math.toRadians(otherAngel)) / Math
.sin(Math.toRadians(angelPart)));
return new Dimension((int) (radius * 2 + largestDiameter), (int) (radius * 2 + largestDiameter));
}
/**
* this method arranges the components within the container by setting their relative x,y values as well as their width,height
* even if the size allocated to this container is smaller than the one returned in the getPrefferedSize method this method will still arrange
* the components in a nice circle but there will be some overlapping.
*/
public void layoutContainer(Container parent)
{
int components = parent.getComponentCount();
double angelPart = 360f / components;
Style parentStyle = parent.getStyle();
int centerPosX = (parent.getLayoutWidth() - parentStyle.getMargin(Component.LEFT) - parentStyle
.getMargin(Component.RIGHT))
/ 2 + parentStyle.getMargin(Component.LEFT);
int centerPosY = (parent.getLayoutHeight() - parentStyle.getMargin(Component.TOP) - parentStyle
.getMargin(Component.BOTTOM))
/ 2 + parentStyle.getMargin(Component.TOP);
double largestDiameter = 0;
for (int iter = 0; iter < components; iter++)
{
Component current = parent.getComponentAt(iter);
Dimension d = current.getPreferredSize();
largestDiameter = Math.max(largestDiameter, Math.sqrt(d.getWidth() * d.getWidth() + d.getHeight()
* d.getHeight()));
}
int radius = (int) (Math.min(parent.getLayoutWidth() - largestDiameter, parent.getLayoutHeight()
- largestDiameter) / 2);
for (int iter = 0; iter < components; iter++)
{
Component current = parent.getComponentAt(iter);
Dimension d = current.getPreferredSize();
current.setSize(d);
double radianAgnel = Math.toRadians(startAngel + clockWise * iter * angelPart);
current.setX(centerPosX + (int) (radius * Math.cos(radianAgnel)) - current.getWidth() / 2);
current.setY(centerPosY + (int) (radius * Math.sin(radianAgnel)) - current.getHeight() / 2);
}
}
}
Screenshots
The images below shows how different number of components are arrange in the center container using the CircularLayout.
Summary
In this article we focused on creating a new layout for LWUIT, you can think of other layouts you wish to have and implement them yourself to create new and exciting UI for your apps.



Contents
Hamishwillee - Subedited
Hi Shaii
This is a fairly well written, straightforward and useful article. I have subedited it for English, making changes like - capitals for first letter in sentence, grammar changes, acronyms (like LWUIT) capitalised. I have also done some wiki changes using Icode to mark up inline code elements and increased the size of the screenshots at the end. Please review and confirm that I haven't accidentally changed the meaning of your text.
My suggestions for improvement:
Lastly, the code is a bit of a "code dump". While it is slightly obvious what you are doing, it might be good to comment a bit more on how you've met the "requirements" of the abstract API. Also to state what will happen if you use more components than there is room for (ie "what are the limitations of this component")
Thanks for competing. I like this.
Regards
Hamishhamishwillee 10:20, 30 July 2012 (EEST)
Shaii - Changes
Hey Hamish,
Thank you for your suggestions.
I've added the external links as you suggested and edited/cropped the images to remove the "window frame" i've used the same screenshots images template i saw on this featured article http://www.developer.nokia.com/Community/Wiki/Implementing_Pinch_zooming_with_Gesture_API_for_Maps_in_Java_ME i also placed the 8 components image in the introduction part. Lastly i've added some comments inside the code to help people understand it better in addition to the explenation in the article itself.
Regards,
Shaishaii 01:16, 31 July 2012 (EEST)
Hamishwillee - Looks much better
Hi Shaii
Thank you very much!
I made one minor change, which was to make the first image a block component - ie so that the text didn't try to wrap around it.
Regards
Hamishhamishwillee 04:46, 31 July 2012 (EEST)
Skalogir - Code styling and enhancements
Hi Shaii,
Very nice effort and thinking outside the box.
A few suggestions from me code-wise
1. By default, the virtual keypad is launched from Action Button 2 (top left) in Canvas applications. You can disable it by adding this line inside the constructor of your main MIDlet:
2. Java code styling for empty spaces: In order to make your code more readable, you could add one space before and after each operator or comma, according to the standard Java conventions. For example these changes could be performed
Original:
Corrected:
Original:
Corrected:
Original:
Corrected:
Original:
Corrected:
3. Java code styling for opening/closing brackets:
There are two standard conventions for opening or closing brackets. Either
or
We typically follow one or the other convention throughout the code, but we don't combine them. You might want to change the way you open your public class statements.
4. The buttons cover a large part of the screen. Why not use Commands instead of Buttons. Your exit Command could be the standard Series 40 Back Command if you follow this code: