MenuDialog with Icons code

2 views
Skip to first unread message

rafa

unread,
Mar 26, 2009, 7:14:35 PM3/26/09
to J4ME
Hi,
I wanted a Menu dialog that can display an icon next to the text.
Moreover, I imagine a "Menu" where there are icons -probably 2 in each
row- with text below them for the user to click.
After reading the threads: "Container component " (http://
groups.google.com/group/j4me/browse_thread/thread/59fcd040065b9986)
and "about menu option" (http://groups.google.com/group/j4me/
browse_thread/thread/488751d5d1b6a6c8/27dd80ae0) I decided to impement
it,
To do that, I created a MenuOptionX and MenuItemX classes (similar
to MenuOption and MenuItem) and modified Menu class adding an
overloaded method appendMenuOption. I also changed the Menu.selection
() method.
The idea is that Menu can receive any component -a component can
draw itself- and some class -may be the same component- that can
handle the 'selcetion' event on it. That's why I created the
Menu.appendMenuOption(Component option, MenuItemX callable) method

With the changes I described, I was able to have a Picture component
instead of text (label) in Menu (see class PictureX) . However, I was
unable to have both text and picture in any layout. Or to have 2 icons
in a row.

Then I used the "Container component" created by Jean-Marie, changed
it a bit, and extended it to ContainerComponentX. Now I'm able to have
a Menu entry with an icon or many icons/labels in the same row (see
the picture).

I modified the UIDemoMidlet to show some examples (see the attached
picture).

Attached is the code. Feel free to add it to the trunk if you think
it can be useful.

Regards,
Rafa

PS the added/modified files are:
src/org/j4me/ui/Menu.java
src/org/j4me/ui/MenuItemX.java
src/org/j4me/ui/components/MenuOptionX.java
examples/org/j4me/examples/ui/UIDemoMidlet.java
examples/org/j4me/examples/ui/components/ContainerComponent.java (not
mine)
examples/org/j4me/examples/ui/components/ContainerComponentX.java
examples/org/j4me/examples/ui/components/LabelX.java
examples/org/j4me/examples/ui/components/PictureX.java

Dean Browne

unread,
Mar 26, 2009, 7:28:04 PM3/26/09
to j4...@googlegroups.com
Thanks!

rafa

unread,
Mar 26, 2009, 7:31:29 PM3/26/09
to J4ME
Well, I cant attach the files. Here is the code:
--------------------------------------------------------
src/org/j4me/ui/Menu.java
--------------------------------------------------------
package org.j4me.ui;

import org.j4me.ui.components.*;

/**
* The <code>Menu</code> class is used for creating the application's
menus.
* <p>
* J2ME devices have small screens and are not all very responsive to
scrolling.
* However, they do have keypads. The <code>Menu</code> class
respects this and
* limits menus to a total of 9 possible choices (1-9) plus "Exit".
Usually all
* the choices can be seen on a single screen and selected with a
single button.
* <p>
* Override this class to change how the menu is painted for your
application.
*/
public class Menu
extends Dialog
{
/**
* The screen that invoked this one or <code>null</code> if there is
no
* previous screen.
*/
protected DeviceScreen previous;

/**
* Constructs a menu.
*/
public Menu ()
{
// No spacing between components.
// The MenuOption component will add spacing for us.
setSpacing( 0 );

// Add the menu bar.
Theme theme = UIManager.getTheme();
String rightMenuText = theme.getMenuTextForOK();
setMenuText( null, rightMenuText );
}

/**
* Constructs a menu.
*
* @param name is the title for this menu, for example "Main Menu".
It
* appears at the top of the screen in the title area.
* @param previous is the screen to return to if the user cancels
this.
*/
public Menu (String name, DeviceScreen previous)
{
this();

this.previous = previous;

setTitle( name );
setPrevious( previous );
}

/**
* Sets the screen to return to if the user cancels this menu. If
* <code>previous</code> is <code>null</code>, there will be no
"Cancel" button.
*
* @param previous is the screen to go to if the user presses
"Cancel".
*/
public void setPrevious (DeviceScreen previous)
{
// Record the previous screen.
this.previous = previous;

// Set the menu text.
Theme theme = UIManager.getTheme();
String leftMenuText = (previous == null ? null :
theme.getMenuTextForCancel());
String rightMenuText = theme.getMenuTextForOK();
setMenuText( leftMenuText, rightMenuText );
}

/**
* Appends a new menu option to this menu.
*
* @param option is the menu item to add.
*/
public void appendMenuOption (MenuItem option)
{
MenuOption choice = new MenuOption( option );
append( choice );
}

/**
* Appends a new menu option to this menu.
*
* @param option is the menu item to add.
*/
public void appendMenuOption (Component option, MenuItemX callable)
{
MenuOptionX choice = new MenuOptionX( option, callable );
append(choice);
}




/**
* Appends a screen as a menu option. If selected the screen will be
* shown. The screen's title is used as its text.
*
* @param option is screen to add as a menu item.
*/
public void appendMenuOption (DeviceScreen option)
{
MenuOption choice = new MenuOption( option );
append( choice );
}

/**
* Appends a screen as a menu option. If selected the screen will be
* shown.
*
* @param text is string that appears in the menu option.
* @param option is screen to add as a menu item.
*/
public void appendMenuOption (String text, DeviceScreen option)
{
MenuOption choice = new MenuOption( text, option );
append( choice );
}

/**
* Appends another menu as a menu option. The submenu will have an
* arrow next to it to indicate to the user it is another menu.
* <p>
* To use a <code>Menu</code> as a screen and not a submenu call the
* <code>appendMenuOption</code> method instead.
*
* @param submenu is the screen to add as a menu item.
*/
public void appendSubmenu (Menu submenu)
{
MenuOption choice = new MenuOption( submenu, true );
append( choice );
}

/**
* The left menu button takes the user back to the previous screen.
* If there is no previous screen it has no effect.
*/
protected void declineNotify ()
{
// Go back to the previous screen.
if ( previous != null )
{
previous.show();
}

// Continue processing the event.
super.declineNotify();
}

/**
* The right menu button selects the highlighted menu item.
*/
protected void acceptNotify ()
{
// Go to the highlighted screen.
int highlighted = getSelected();
selection( highlighted );

// Continue processing the event.
super.acceptNotify();
}

/**
* Responds to key press events that are specific to menu screens.
* Selects the highlighted menu choice if the joystick's
* <code>FIRE</code> key is pressed. Scrolls from the last choice to
* the first choice if <code>DOWN</code> is pressed and from the
first to
* the last if <code>UP</code> is pressed.
*
* @param key is the key code of the button the user pressed.
*/
protected void keyPressed (int key)
{
boolean goToFirst = false;
boolean goToLast = false;

// Wrap the scroll around the screen?
if ( key == DOWN )
{
if ( getSelected() == size() - 1 )
{
// Go to the first menu choice.
goToFirst = true;
}
}
else if ( key == UP )
{
if ( (getSelected() == 0) && (size() > 1) )
{
// Go to the last menu choice.
goToLast = true;
}
}

// Process the key event.
super.keyPressed( key );

// Were we going to the first or last menu choice?
// Only do these after super.keyPressed(). Otherwise
// keyPressed() will scroll again so we'll actually wind
// up on the second or second-to-last menu choice.
if ( goToFirst )
{
setSelected( 0 );
}
else if ( goToLast )
{
setSelected( size() - 1 );
}
}

/**
* Selects a menu item.
*
* @param selection is the index of <code>choice</code> that is
selected.
*/
private void selection (int selection)
{
Component component = get( selection );

if ( component instanceof MenuOption )
{
MenuOption chosen = (MenuOption)component;

// Record this as the selection.
setSelected( selection );

// Perform the selection operation.
chosen.select();
}
else if ( component instanceof MenuOptionX )
{
MenuOptionX chosen = (MenuOptionX)component;

// Record this as the selection.
setSelected( selection );

// Perform the selection operation.
chosen.select();
}

}
}
--------------------------------------------------------

--------------------------------------------------------
src/org/j4me/ui/MenuItemX.java
--------------------------------------------------------
package org.j4me.ui;

/**
* Implementing classes can be used as menu choices that draw
themselves in a <code>Menu</code>.
*/
public interface MenuItemX
{
/**
* Called when the user selects this choice from the menu.
*/
public void onSelection ();

}
--------------------------------------------------------

--------------------------------------------------------
src/org/j4me/ui/components/MenuOptionX.java
--------------------------------------------------------
package org.j4me.ui.components;



import javax.microedition.lcdui.*;

import org.j4me.ui.*;



/**

* The <code>Menu</code> screen uses one of these <code>MenuOption</
code> components

* for each menu choice.

* <p>

* The default implementation shows the choice number on the left,
then

* the text for the choice, and an arrow on the right if it is a
submenu.

* The text is clipped if it runs over a single line. This keeps all

* menu items the same height.

*

* @see Menu

*/

public class MenuOptionX

extends Component

{

/**

* The number of pixels that separates the text and submenu

* indicator from the left and right edges of the component.

* Increasing this number reduces the width of usuable space

* to write the menu choice's text.

*/

private static final int HORIZONTAL_MARGIN = 3;



/**

* The number of pixels that separate the text from the top

* and bottom of the menu indicator. Increasing this value

* also increases the spacing between menu items by a factor

* of two (i.e. the bottom of this one plus top of the next).

*/

private static final int VERTICAL_MARGIN = HORIZONTAL_MARGIN;



/**

* The <code>MenuItem</code> encapsulated by this component. If this

* component is for a <code>DeviceScreen</code> option, this will be

* <code>null</code>.

*/

private final MenuItemX menuItem;

private final Component component;







/**

* Creates a new <code>MenuOptionX</code> component that encapsulates
a

* <code>MenuItem</code>.

*

* @param choice is the command that is represented by this
component.

*/

public MenuOptionX (Component component, MenuItemX choice)

{

if ( choice == null )

{

throw new IllegalArgumentException("choice cannot be null");

}



this.menuItem = choice;

this.component= component;

}



/**

* An event raised whenever the component is made visible on the
screen.

* This is called before the <code>paintComponent</code> method.

*/

protected void showNotify ()

{

component.visible(true);



// Continue processing the event.

super.showNotify();

}



/**

* An event raised whenever the component is removed from the screen.

*/

protected void hideNotify ()

{

// Pass the event to contained components.

component.visible( false );



// Continue processing the event.

super.hideNotify();

}



/**

* Paints a <code>MenuOption</code>. On the left is the choice
number in

* a box. The middle has the text for the choice. If it is a
submenu

* the right has an arrow.

*

* @param g is the <code>Graphics</code> object to paint with.

* @param theme is the application's theme used to paint the menu
item.

* @param width is the width of the menu item area in pixels.

* @param height is the height of the menu item area in pixels.

* @param selected is <code>true</code> if this is the currently
highlighted

* menu choice.

*

* @see org.j4me.ui.components.Component#paintComponent
(javax.microedition.lcdui.Graphics, org.j4me.ui.Theme, int, int,
boolean)

*/

protected void paintComponent (Graphics g, Theme theme, int width,
int height, boolean selected)

{

component.paintComponent(g, theme, width, height, selected);

}





/**

* Returns the size of the menu choice. It will be one line of text

* high and as wide as the screen.

*

* @see org.j4me.ui.components.Component#getPreferredComponentSize
(org.j4me.ui.Theme, int, int)

*/

public int[] getPreferredComponentSize (Theme theme, int
viewportWidth, int viewportHeight)

{

return component.getPreferredComponentSize(theme, viewportWidth,
viewportHeight);

}



/**

* @return <code>true</code> because this component accepts user
input.

*/

public boolean acceptsInput ()

{

return true;

}



public void select(){

if (null != menuItem){

menuItem.onSelection();

}

}



/**

* Called when the user presses any key.

*

* @param key is code of the key that was pressed.

*

* @see Component#keyPressed(int)

*/

public void keyPressed (int key)

{

// The joystick's fire button means to select this item.

if ( key == DeviceScreen.FIRE )

{

select();

}

else

{

component.keyPressed(key);

}

super.keyPressed(key);



//component.keyPressed(key);



// Continue processing the key event.

//super.keyPressed( key );

}



/**

* Called when the pointer is pressed.

*

* @param x is the horizontal location where the pointer was pressed

* relative to the top-left corner of the component.

* @param y is the vertical location where the pointer was pressed

* relative to the top-left corner of the component.

*/

public void pointerPressed (int x, int y)

{

// If anywhere on the menu item is pressed it has been selected.

select();

//component.pointerPressed(x, y);



// Continue processing the pointer event.

super.pointerPressed( x, y );

}

}

--------------------------------------------------------

--------------------------------------------------------
examples/org/j4me/examples/ui/UIDemoMidlet.java
--------------------------------------------------------
package org.j4me.examples.ui;



import java.io.IOException;



import javax.microedition.lcdui.Graphics;

import javax.microedition.midlet.MIDlet;

import javax.microedition.midlet.MIDletStateChangeException;



import org.j4me.examples.ui.components.CheckBoxExample;

import org.j4me.examples.ui.components.ContainerComponentX;

import org.j4me.examples.ui.components.LabelExample;

import org.j4me.examples.ui.components.LabelX;

import org.j4me.examples.ui.components.PictureExample;

import org.j4me.examples.ui.components.PictureX;

import org.j4me.examples.ui.components.ProgressBarExample;

import org.j4me.examples.ui.components.RadioButtonExample;

import org.j4me.examples.ui.components.ScrollbarExample;

import org.j4me.examples.ui.components.TextBoxExample;

import org.j4me.examples.ui.themes.ConsoleTheme;

import org.j4me.examples.ui.themes.GreenTheme;

import org.j4me.examples.ui.themes.RedTheme;

import org.j4me.ui.Menu;

import org.j4me.ui.MenuItem;

import org.j4me.ui.Theme;

import org.j4me.ui.UIManager;

import org.j4me.ui.components.Label;



/**

* The demonstration MIDlet for the J4ME UI.

*/

public class UIDemoMidlet

extends MIDlet

{

/* (non-Javadoc)

* @see javax.microedition.midlet.MIDlet#startApp()

*/

protected void startApp () throws MIDletStateChangeException

{

// Initialize the J4ME UI manager.

UIManager.init( this );



// The theme is the default represented <code>Theme</code> class.

// To change it, create a new <code>Theme</code>-derived object and
call

// <code>UIManager.setTheme</code>.



// The first screen is a menu to choose among the example screens.

Menu menu = new Menu( "UI Examples", null );



// Create a submenu for showing component example screens.

Menu componentExampleMenu = new Menu( "Component Examples", menu );

menu.appendSubmenu( componentExampleMenu );



LabelExample labelExample = new LabelExample
( componentExampleMenu );

componentExampleMenu.appendMenuOption( labelExample );



ProgressBarExample progressBarExample = new ProgressBarExample
( componentExampleMenu );

componentExampleMenu.appendMenuOption( progressBarExample );



// ---------------- This draws a picture only as menu item

try {

PictureX pic = new PictureX();

pic.setHorizontalAlignment( Graphics.HCENTER );

pic.setImage("/J4ME.png");

componentExampleMenu.appendMenuOption(pic,pic);

} catch (Exception e) {

e.printStackTrace();

}

// ----------------



TextBoxExample textBoxExample = new TextBoxExample
( componentExampleMenu );

componentExampleMenu.appendMenuOption( textBoxExample );



RadioButtonExample radioButtonExample = new RadioButtonExample
( componentExampleMenu );

componentExampleMenu.appendMenuOption( radioButtonExample );



// ---------------- This draws a label with an icon as menu item

try {

PictureX pic = new PictureX();

pic.setHorizontalAlignment( Graphics.HCENTER );

pic.setImage("/J4ME.png");

Label lb= new Label();

lb.setLabel("000");

lb.setHorizontalAlignment(Graphics.HCENTER);

ContainerComponentX cc= new ContainerComponentX
(ContainerComponentX.LAYOUT_HORIZONTAL);

cc.paintBg(true);

//cc.setKnowHowToPaintBg(false);

cc.append(pic);

cc.append(lb);

componentExampleMenu.appendMenuOption(cc,cc );

}catch (Exception e) {

e.printStackTrace();

}

// ----------------



CheckBoxExample checkBoxExample = new CheckBoxExample
( componentExampleMenu );

componentExampleMenu.appendMenuOption( checkBoxExample );



ScrollbarExample scrollbarExample = new ScrollbarExample
( componentExampleMenu );

componentExampleMenu.appendMenuOption( scrollbarExample );



// ---------------- This draws 3 icons, each one with a label below.

// each icon/label can be selected with the left/right arrows



try {

// label+icon 1

PictureX pic1 = new PictureX();

pic1.setHorizontalAlignment( Graphics.HCENTER );

pic1.setImage("/J4ME.png");

LabelX lb1= new LabelX();

lb1.setLabel("111");

lb1.setHorizontalAlignment(Graphics.HCENTER);

ContainerComponentX cc1= new ContainerComponentX
(ContainerComponentX.LAYOUT_VERTICAL);

cc1.paintBg(true);

cc1.append(pic1);

cc1.append(lb1);





// label+icon 2

PictureX pic2 = new PictureX();

pic2.setHorizontalAlignment( Graphics.HCENTER );

pic2.setImage("/tt.png");

Label lb2= new Label();

lb2.setLabel("222");

lb2.setHorizontalAlignment(Graphics.HCENTER);

ContainerComponentX cc2= new ContainerComponentX
(ContainerComponentX.LAYOUT_VERTICAL);

cc2.paintBg(true);

cc2.append(pic2);

cc2.append(lb2);





// label+icon 3

PictureX pic3 = new PictureX();

pic3.setHorizontalAlignment( Graphics.HCENTER );

pic3.setImage("/J4ME.png");

Label lb3= new Label();

lb3.setLabel("333");

lb3.setHorizontalAlignment(Graphics.HCENTER);

ContainerComponentX cc3= new ContainerComponentX
(ContainerComponentX.LAYOUT_VERTICAL);

cc3.paintBg(true);

cc3.append(pic3);

cc3.append(lb3);



// add all the label/icons in the same menu item row

ContainerComponentX cc4= new ContainerComponentX
(ContainerComponentX.LAYOUT_HORIZONTAL);

cc4.paintBg(false);

cc4.setHorizontalAlignment(Graphics.HCENTER);

cc4.append(cc1);

cc4.append(cc2);

cc4.append(cc3);

componentExampleMenu.appendMenuOption( cc4, cc4 );





} catch (IOException e) {

e.printStackTrace();

}



PictureExample pictureExample = new PictureExample
( componentExampleMenu );

componentExampleMenu.appendMenuOption( pictureExample );





// Create a submenu showing different example themes.

Menu themesMenu = new Menu( "Themes", menu );

menu.appendSubmenu( themesMenu );



ThemeMenuItem defaultTheme = new ThemeMenuItem( "Blue (Default)",
new Theme() );

themesMenu.appendMenuOption( defaultTheme );



ThemeMenuItem greenTheme = new ThemeMenuItem( "Green", new GreenTheme
() );

themesMenu.appendMenuOption( greenTheme );



ThemeMenuItem redTheme = new ThemeMenuItem( "Red", new RedTheme() );

themesMenu.appendMenuOption( redTheme );



ThemeMenuItem consoleTheme = new ThemeMenuItem( "Console", new
ConsoleTheme() );

themesMenu.appendMenuOption( consoleTheme );



// Attach the examples.

KeyCode keyCode = new KeyCode( menu );

menu.appendMenuOption( keyCode );



EtchASketch etchAsketch = new EtchASketch( menu );

menu.appendMenuOption( etchAsketch );



Stopwatch stopwatch = new Stopwatch( menu );

menu.appendMenuOption( stopwatch );



// Attach an exit option.

menu.appendMenuOption( new MenuItem()

{

public String getText ()

{

return "Exit";

}



public void onSelection ()

{

UIDemoMidlet.this.notifyDestroyed();

}

} );



// Show the menu.

menu.show();

}



/* (non-Javadoc)

* @see javax.microedition.midlet.MIDlet#pauseApp()

*/

protected void pauseApp ()

{

// The application has no state so ignore pauses.

}



/* (non-Javadoc)

* @see javax.microedition.midlet.MIDlet#destroyApp(boolean)

*/

protected void destroyApp (boolean cleanup) throws
MIDletStateChangeException

{

// The application holds no resources that need cleanup.

}

}



/**

* Options available from a menu that change the application's theme.

*/

class ThemeMenuItem

implements MenuItem

{

private final String name;

private final Theme theme;



public ThemeMenuItem (String name, Theme theme)

{

this.name = name;

this.theme = theme;

}



public String getText ()

{

// The name as it appears in the menu.

return name;

}



public void onSelection ()

{

// Applies a theme to the example midlet.

UIManager.setTheme( theme );



// Repaint the screen so the changes take effect.

UIManager.getScreen().repaint();

}

}

---------------------------------------------------


---------------------------------------------------
examples/org/j4me/examples/ui/components/ContainerComponent.java (not
mine)
---------------------------------------------------
package org.j4me.examples.ui.components;

/**
* Copied from Jean-Marie Hermelin's post:
* http://groups.google.com/group/j4me/browse_thread/thread/59fcd040065b9986
* Changed private to protected in selectNextComponent. rafa.
*
*/

import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.lcdui.Graphics;

import org.j4me.ui.DeviceScreen;
import org.j4me.ui.Theme;
import org.j4me.ui.UIManager;
import org.j4me.ui.components.Component;

public class ContainerComponent extends Component {
/**
* The collection of all components on this form. Components are
displayed
* as ordered from top to bottom.
*/
private Vector components = new Vector();
/**
* The index of <code>component</code> the user currently has
highlighted.
* If this is not an index of <code>component</code> nothing is
highlighted.
*/
private int highlightedComponent = -1;

/**
* The number of pixels above and below components.
*/
private int spacing = 1;

/**
* the location { x, y, width, height} of the components
*/
private int[][] location;
/**
* the actual preferred size for this component
*/
private int[] _preferredSize;

/**
* Vertical Layout FLAG
*/
public static final int LAYOUT_VERTICAL = 0;

/**
* Horizontal Layout FLAG
*/

public static final int LAYOUT_HORIZONTAL = 1;
/**
* actual layout
*/
private int _layout = LAYOUT_VERTICAL;

/**
* Implicitly called by derived classes to setup a new J4ME form.
* @param _layout
*/
public ContainerComponent(int layout) {
super();
_layout = layout;
visible(true);
}

/**
* Called immediately before this screen is replaced by another
screen.
* <p>
* Notifies all the components they are hidden. Classes that
override
* this method should be sure to call <code>super.onDeselection</
code>.
*
* @see DeviceScreen#hideNotify()
*/
public void hideNotify() {
// Hide all the components on the screen.
Enumeration e = components.elements();
while (e.hasMoreElements()) {
Component c = (Component) e.nextElement();
c.visible(false);
}
// Continue deselection.
super.hideNotify();
}

/**
* Adds the <code>component</code> to the end of this form.
*
* @param component is the UI component to add to the bottom of the
form.
*/
public void append(Component component) {
clearLayout();
components.addElement(component);
}

/**
* Inserts the <code>component</code> in this form at the specified
<code>index</code>.
* Each component on this form with an index greater or equal to the
* specified <code>index</code> is shifted upward to have an index
one greater
* than the value it had previously.
*
* @param component is the UI component to insert.
* @param index is where to insert <code>component</code> on the
form. It must
* greater than or equal to 0 and less than or equal to the number
of
* components already on the form.
* @throws ArrayIndexOutOfBoundsException if the index was invalid.
*/
public void insert(Component component, int index) {
clearLayout();
components.insertElementAt(component, index);
}

/**
* Sets the <code>component</code> in this form at the specified
<code>index</code>.
* The previous component at that position is discarded.
*
* @param component is the UI component to set to.
* @param index is where to set <code>component</code> on the form.
It must
* greater than or equal to 0 and less than the number of
* components already on the form.
* @throws ArrayIndexOutOfBoundsException if the index was invalid.
*/
public void set(Component component, int index) {
clearLayout();
components.setElementAt(component, index);
}

/**
* Removes the first occurrence of the <code>component</code> from
this form.
* If <code>component</code> is found on this form, each component on
the form
* with an index greater or equal to the <code>component</code>'s
index is
* shifted downward to have an index one smaller than the value it
had
* previously.
*
* @param component is the UI component to remove.
*/
public void delete(Component component) {
int index = components.indexOf(component);
delete(index);
}

/**
* Deletes the <code>component</code> at the specified <code>index</
code>. Each
* component in this vector with an index greater or equal to the
* specified index is shifted downward to have an index one smaller
* than the value it had previously.
*
* @param index is the index of the component to remove. It must be
* a value greater than or equal to 0 and less than the current
* number of components on the form.
* @throws ArrayIndexOutOfBoundsException if the index was invalid.
*/
public void delete(int index) {
clearLayout();
components.removeElementAt(index);
if (highlightedComponent == index) {
highlightedComponent = -1;
} else if (highlightedComponent > index) {
highlightedComponent--;
}
}

/**
* Removes all of the components from this form.
*/
public void deleteAll() {
clearLayout();
components.removeAllElements();
highlightedComponent = -1;
}

/**
* Returns an enumeration of the components on this form.
*
* @return An enumeration of the components on this form.
*/
public Enumeration components() {
clearLayout();
return components.elements();
}

/**
* Returns the number of components on this form.
*
* @return The number of components on this form.
*/
public int size() {
return components.size();
}

/**
* Returns the component at the specified index.
*
* @param index is the value into the component list to get.
* @return The component at <code>index</code> or <code>null</code>
if the
* index is invalid.
*/
public Component get(int index) {
Component c = null;
if ((index >= 0) && (index < components.size())) {
c = (Component) components.elementAt(index);
}
return c;
}

/**
* Returns the index of the currently selected component. It is
* the one the user can currently enter data into.
*
* @return The index of the component on the form that is currently
* selected.
*/
public int getSelected() {
if (highlightedComponent < 0) {
return 0;
} else {
return highlightedComponent;
}
}

/**
* Returns the index of the component that contains the given pixel.
* If no component is at that location, for example it is in the
* spacing between components, then <code>-1</code> is returned.
* <p>
* This method assumes that the click is relative to the form
* area. It may not address the title bar, menu bar, or a
* scroll bar.
*
* @param x is the X-coordinate of the pixel on the form.
* @param y is the Y-coordinate of the pixel on the form.
* @return The index of the component containing the pixel
* (<code>x</code>, <code>y</code>) or <code>-1</code> if no
component contains it.
*/
private int getAt(int x, int y) {
int matched = -1;
// Get the absolute position of y on the form.
int absY = getY() + y;
int absX = getX() + x;
// Walk the list of component positions until absY is found.
for (int i = 0; i < components.size(); i++) {
// Get the dimensions of this component.
Component c = (Component) components.elementAt(i);
int top = c.getY();
int bottom = top + c.getHeight();
int left = c.getX();
int right = left + c.getWidth();
// Does the point fall within this component?
if ((absY >= top) && (absY < bottom) && (absX >= left) && (absX <
right)) {
// This is the component that (x, y) falls within.
matched = i;
break;
}
}
return matched;
}


/**

additionnaly I modify the Dialog.getAt method to behave on absolute
coordinates (this is mandatory if you want the pointer to react as
expected)

private int getAt (int x, int y)
{

Enumeration elts = components.elements();
int count = 0;
while(elts.hasMoreElements())
{
Component c = (Component) elts.nextElement();
int top = c.getY();
int bottom = top+c.getHeight();

int left = c.getX();
int right = c.getWidth();

// Does the point fall within this component?
if ( (y >= top) && (y < bottom) &&
(x >= left) && (x < right) )
{
// This is the component that (x, y) falls within.
return count;
}
count++;

}

return -1;
}


*/
/**
* Sets the selected component. It is the one the user can input
* data into and that the screen is scrolled to.
*
* @param index is the new selected component.
*/
public void setSelected(int index) {
if ((index < 0) || (index >= components.size())) {
throw new IndexOutOfBoundsException(String.valueOf(index));
}
highlightedComponent = index;
}

/**
* Sets the selected component. It is the one the user can input
* data into and that the screen is scrolled to.
*
* @param component is the new selected component. If it is not
* on the form this has no effect.
*/
public void setSelected(Component component) {
int index = 0;
// Walk the list of components until we find it.
Enumeration e = components.elements();
while (e.hasMoreElements()) {
Component c = (Component) e.nextElement();
if (c == component) {
// This is the component.
break;
}
index++;
}
// Set the component as the selected one.
if (index < size()) {
setSelected(index);
}
}



/**
* Returns the vertical spacing between components.
*
* @return The number of pixels that vertically separate components.
*/
public int getSpacing() {
return spacing;
}

/**
* Sets the vertical spacing between components.
*
* @param spacing is the number of pixels that vertically separates
* components. Values less than 0 are be ignored.
*/
public void setSpacing(int spacing) {
if ((spacing >= 0) && (this.spacing != spacing)) {
this.spacing = spacing;
// Recalculate the layout with the new spacings later.
clearLayout();
}
}

/**
* Whenever the form is altered this method should be called to clear
* the layout. The layout will be re-established during the next
painting.
*/
private synchronized void clearLayout() {
location = null;
_preferredSize = null;
}

/**
* Goes through all of the components and determines their vertical
* positioning. The form's overall height, the sum of all the
* components, is set in the <code>height</code> member variable.
*
* @param theme is the application's current <code>Theme</code>.
* @param widht is the number of pixels wide the screen is.
* @param height is the number of pixels high the screen is.
*/
private synchronized int[] calculateLayout(Theme theme, int width,
int height) {
_preferredSize = new int[] { 0, 0 };
//Log.info("Container " + width + "," + height);
location = new int[components.size()][4];
// Scroll through the components determining the vertical position
of each one.
Enumeration list = components.elements();



int top = 0;
int left = 0;
for (int i = 0; list.hasMoreElements(); i++) {
// Calculate the position of the next component.
Component c = (Component) list.nextElement();

int[] dimensions = c.getPreferredSize(theme, width, height);
location[i][0] = left;
location[i][1] = top;
location[i][2] = dimensions[0];
location[i][3] = dimensions[1];
//Log.info("Component " + c + "," + location[i][0] + "," + location
[i][1] + "," + location[i][2] + "/" + width+"," + location[i][3]);
if (_layout == LAYOUT_HORIZONTAL) {
left += dimensions[0] + spacing;
if ((dimensions[1] + top) > _preferredSize[1])
_preferredSize[1] = dimensions[1] + top ;
_preferredSize[0] = left ;
} else if (_layout == LAYOUT_VERTICAL) {
top += dimensions[1] + spacing;
if ((dimensions[0] + left) > _preferredSize[0])
_preferredSize[0] = dimensions[0] + left ;
_preferredSize[1] = top ;
}
// Is this the first component that can be highlighted?
if (highlightedComponent < 0) {
if (c.acceptsInput()) {
highlightedComponent = i;
}
}
}
//Log.info("Container Size " + _preferredSize[0] + "," +
_preferredSize[1]);
return _preferredSize;
}

/**
* Forces the layout of all components to be recalculated. This
should
* be called whenever this screen or its components are altered. For
* example changing a label may change its size and this method will
* account for that.
*/
public void invalidate() {
// Remove the layout of all components.
clearLayout();
// Recalculate the position of all components.
calculateLayout(UIManager.getTheme(), getWidth(), getHeight());
}

/**
*
*
*
* @param down is <code>true</code> when the form should scroll down
and
* <code>false</code> when it should scroll up.
*/
protected boolean selectNextComponent(boolean down) {
// Get the dimensions of the current highlighted component.
//int current = (highlightedComponent >= 0 ? highlightedComponent :
0);
// Get the next component that can be highlighted.
int nextHighlighted = highlightedComponent;
if (down) {
int max = size();
for (int i = highlightedComponent + 1; i < max; i++) {
Component c = get(i);
if (c.acceptsInput()) {
nextHighlighted = i;
break;
}
}
} else // up
{
for (int i = highlightedComponent - 1; i >= 0; i--) {
Component c = get(i);
if (c.acceptsInput()) {
nextHighlighted = i;
break;
}
}
}
boolean modified = (highlightedComponent != nextHighlighted);
// Change the highlighted component.
highlightedComponent = nextHighlighted;
// Redraw the component
//Log.info("repaint" + this + " [" + getX() + "," + getY() + "," +
getWidth() + "," + getHeight() +"]");

repaint();
//UIManager.getScreen().repaint();
return modified;
}

/**
* Called when a key is pressed. It can be identified using the
* constants defined in this class.
*
* @param keyCode is the key code of the key that was pressed.
*/
public void keyPressed(int keyCode) {
// Forward the event to the current component.
Component c = get(highlightedComponent);
if (c != null) {
c.keyPressed(keyCode);
return;
}
// Scrolling vertically?
if (keyCode == DeviceScreen.UP) {
selectNextComponent(false);
} else if (keyCode == DeviceScreen.DOWN) {
selectNextComponent(true);
}
// Continue processing the event.
super.keyPressed(keyCode);
}

/**
* Called when a key is repeated (held down). It can be identified
using the
* constants defined in this class.
*
* @param keyCode is the key code of the key that was held down.
*/
public void keyRepeated(int keyCode) {
// Forward the event to the current component.
Component c = get(highlightedComponent);
if (c != null) {
c.keyRepeated(keyCode);
return ;
}
// Continue processing the event.
super.keyRepeated(keyCode);
}

/**
* Called when a key is released. It can be identified using the
* constants defined in this class.
*
* @param keyCode is the key code of the key that was released.
*/
public void keyReleased(int keyCode) {
// Forward the event to the current component.
Component c = get(highlightedComponent);
if (c != null) {
c.keyReleased(keyCode);
return ;
}
// Continue processing the event.
super.keyReleased(keyCode);
}

/**
* Called when the pointer is pressed.
*
* @param x is the horizontal location where the pointer was pressed.
* @param y is the vertical location where the pointer was pressed.
*/
public void pointerPressed(int x, int y) {
// Highlight the component.
highlightedComponent = getAt(x, y);
// Forward the event to the component for processing.
Component c = get(highlightedComponent);
if (c != null) {
// Adjust the click position relative to the component.
int px = x - location[highlightedComponent][0];
int py = y - location[highlightedComponent][1];
c.pointerPressed(px, py);
return;
}
// Continue processing the event.
super.pointerPressed(x, y);
}

/**
* Called when the pointer is dragged.
*
* @param x is the horizontal location where the pointer was dragged.
* @param y is the vertical location where the pointer was dragged.
*/
public void pointerDragged(int x, int y) {
// Forward the event to the current component.
Component c = get(highlightedComponent);
if (c != null) {
c.pointerDragged(x, y);
return;
}
// Continue processing the event.
super.pointerDragged(x, y);
}

public int[] getPreferredComponentSize(Theme theme, int
viewportWidth, int viewportHeight) {

return calculateLayout(theme, viewportWidth, viewportHeight);
}

protected void paintComponent(Graphics g, Theme theme, int width, int
height, boolean selected) {
//Log.info("PAINT" + " [" + g.getTranslateX() + "," +
g.getTranslateY() + "," + getWidth() + "," + getHeight() +"]");
//Log.info("paint container " + width +"," + height);
if (selected && components.size() == 0)
paintRect(g, theme, 0, 0, width, height, selected);
// Walk the list of components and paint them.
int formWidth = getWidth();
int topOfComponent = getY();
int bottomOfComponent = topOfComponent + height;

int left = 0;
switch (getHorizontalAlignment()) {
case Graphics.HCENTER:
left = (width - _preferredSize[0]) / 2;
break;
case Graphics.RIGHT:
left = width - _preferredSize[0];
break;
default:
break;
}
for (int i = 0; i < components.size(); i++) {
Component c = (Component) components.elementAt(i);
c.visible(true);
boolean cselected = (i == highlightedComponent) && selected;
int cwidth = location[i][2];
int cheight = location[i][3];
if (_layout == LAYOUT_HORIZONTAL)
cheight = height;
else
cwidth = width;

if((cwidth + location[i][0])> width)
cwidth = width-location[i][0];
if((cheight+location[i][1]) > height)
cheight = height-location[i][1];


c.paint(g, theme, getScreen(), location[i][0]+left, location[i][1],
cwidth, cheight, cselected);
}
}

public boolean acceptsInput() {
Enumeration elts = components.elements();
while(elts.hasMoreElements())
{
if(( (Component)elts.nextElement()).acceptsInput())
return true;
}

return false;
}
}
---------------------------------------------------

---------------------------------------------------
examples/org/j4me/examples/ui/components/ContainerComponentX.java
---------------------------------------------------
package org.j4me.examples.ui.components;


import javax.microedition.lcdui.Graphics;

import org.j4me.ui.DeviceScreen;
import org.j4me.ui.MenuItemX;
import org.j4me.ui.Theme;
import org.j4me.ui.UIManager;
import org.j4me.ui.components.Component;

public class ContainerComponentX extends ContainerComponent implements
MenuItemX {
private static final int HORIZONTAL_MARGIN = 3;
private static final int VERTICAL_MARGIN = 3;

/**
* Implicitly called by derived classes to setup a new J4ME form.
* @param _layout
*/
public ContainerComponentX(int layout) {
super(layout);
}
/**
*
*
*
* @param down is <code>true</code> when the form should scroll down
and
* <code>false</code> when it should scroll up.
*/
// I must overload this, because repaint() -in super- do nothing as
screen is null.
// I should investigate why.
protected boolean selectNextComponent(boolean down) {
boolean modified = super.selectNextComponent(down);
if (modified)
{
// Dont know why can't just call super.repaint();
UIManager.getScreen().repaint();
}
return modified;
}

/**
* Called when a key is pressed. It can be identified using the
* constants defined in this class.
*
* @param keyCode is the key code of the key that was pressed.
*/
public void keyPressed(int keyCode) {
System.err.println("ContainerComponent keyPressed " + keyCode);
// Scrolling vertically?
if (keyCode == DeviceScreen.LEFT) {
selectNextComponent(false);
} else if (keyCode == DeviceScreen.RIGHT) {
selectNextComponent(true);
} else {
// Forward the event to the current component.
Component c = get(getSelected());
if (c != null) {
c.keyPressed(keyCode);
return;
}
}
// Continue processing the event.
super.keyPressed(keyCode);
}


public boolean acceptsInput() {
return true;
}


private boolean paintBg= false;
public boolean paintBg() {
return paintBg;
}

public void paintBg(boolean knowHowToPaintBg) {
this.paintBg = knowHowToPaintBg;
}
protected void paintComponent (Graphics g, Theme theme, int width,
int height, boolean selected)
{
// Paint the background for the menu item.
if ( selected && paintBg)
{
int backgroundColor = theme.getHighlightColor();
g.setColor( backgroundColor );
g.fillRect( 0, 0, width, height );
super.paintComponent(g, theme, width-HORIZONTAL_MARGIN, height-
VERTICAL_MARGIN, selected);
}
else
{
super.paintComponent(g, theme, width, height, selected);
}
}

public void onSelection() {
//System.err.println("**** CntainerComponent onSelectcion");
Component c = get(getSelected());
if (c != null) {
if (c instanceof MenuItemX) {
MenuItemX cc = (MenuItemX) c;
cc.onSelection();
}
else
{
c.keyPressed(DeviceScreen.FIRE);
}
return;
}
}
}
---------------------------------------------------


---------------------------------------------------
examples/org/j4me/examples/ui/components/LabelX.java
---------------------------------------------------
package org.j4me.examples.ui.components;

import org.j4me.ui.MenuItemX;
import org.j4me.ui.components.Label;

public class LabelX extends Label implements MenuItemX {

public void onSelection() {
System.err.println("LabelX was selected: " + getLabel());
}

/**
* Needed when used inside a ContainerComponentX
*/
public boolean acceptsInput() {
return true;
}
}
---------------------------------------------------


---------------------------------------------------
examples/org/j4me/examples/ui/components/PictureX.java
---------------------------------------------------
package org.j4me.examples.ui.components;

import javax.microedition.lcdui.Graphics;

import org.j4me.ui.MenuItemX;
import org.j4me.ui.Theme;
import org.j4me.ui.components.Picture;

public class PictureX extends Picture implements MenuItemX {
private static final int HORIZONTAL_MARGIN = 3;
private static final int VERTICAL_MARGIN = 3;

protected synchronized void paintComponent(Graphics g, Theme theme,
int width, int height, boolean selected) {
if ( selected)
{
int backgroundColor = theme.getHighlightColor();
g.setColor( backgroundColor );
g.fillRect( 0, 0, width, height );
super.paintComponent(g, theme, width-HORIZONTAL_MARGIN, height-
VERTICAL_MARGIN, selected);
}
else
{
super.paintComponent(g, theme, width, height, selected);
}
}

/**
* Needed when used inside a ContainerComponentX
*/
public boolean acceptsInput() {
return true;
}

public void onSelection() {
System.err.println("PictureX was selected ");
}
}


---------------------------------------------------

Rafa
Reply all
Reply to author
Forward
0 new messages