views:

1203

answers:

1

Hi I'm a beginner in BlackBerry programming, I need to replace in my application the default menu (when you press the menu button) by a custom menu, horizontal. The best to describe is I want the same result as the WeatherEye application for BlackBerry...

alt text

I know how to create the default menu, but this one I have no idea! Thank you,

+2  A: 

What you will need to do is:

  • create SizebleVFManager (contentManager) as an extension of VerticalFieldManager
  • set display width and height = (display height - menu height) size to contentManager
  • add contentManager to screen
  • create HorizontalFieldManager (menuManager)
  • create BitmapButtonField (menuButton) as an extension of ButtonField
  • set FieldChangeListeners to menuButtons
  • add menuButtons to menuManager
  • add menuManager to screen

Sample of SizebleVFManager :

class SizebleVFManager extends VerticalFieldManager
{
    int mWidth = 0;
    int mHeight = 0;
    public SizebleVFM(int width, int height, long style) {
        super(style);
        mWidth = width;
        mHeight = height;
    }

    public SizebleVFM(int width, int height) {
        mWidth = width;
        mHeight = height;
    }

    public int getPreferredWidth() {
        return mWidth;
    }

    public int getPreferredHeight() {
        return mHeight;
    }

    protected void sublayout(int width, int height) {
        width = getPreferredWidth();
        height = getPreferredHeight();  
        super.sublayout(width, height); 
        setExtent(width, height);
    }
}

...

SizebleVFManager contentManager = 
    new SizebleVFManager(Display.getWidth(), Display.getHeight(), 
        VERTICAL_SCROLL|VERTICAL_SCROLLBAR);

See also
sample of BitmapButtonField and Toolbar

PS though its better to use standard menu...

UPDATE

If you want to disable default menu functionality, cancel MENU keydown:

protected boolean keyDown(int keycode, int time) {
    if(Keypad.KEY_MENU == Keypad.key(keycode))
    {
        return true;
    }
    else
    return super.keyDown(keycode, time);
}

UPDATE

I've installed that wonderful weather application and understood this sample may be more alike with several improvements:

  • use CyclicHFManager as an extension of HorizontalFieldManager
  • show/hide menuManager on Menu button click

CyclicHFManager is a manager which will keep focus on the same place visually and run all fields over, in cycle. Like in BlackBerry - Custom centered cyclic HorizontalFieldManager

class CyclicHFManager extends HorizontalFieldManager {
    int mFocusedFieldIndex = 0;
    boolean mCyclicTurnedOn = false;

    public void focusChangeNotify(int arg0) {
        super.focusChangeNotify(arg0);
        if (mCyclicTurnedOn) {
            int focusedFieldIndexNew = getFieldWithFocusIndex();
            if (focusedFieldIndexNew != mFocusedFieldIndex) {
                if (focusedFieldIndexNew - mFocusedFieldIndex > 0)
                    switchField(0, getFieldCount() - 1);
                else
                    switchField(getFieldCount() - 1, 0);
            }
        }
        else
        {
            mFocusedFieldIndex = getFieldWithFocusIndex();
        }
    }

    private void switchField(int prevIndex, int newIndex) {
        Field field = getField(prevIndex);
        delete(field);
        insert(field, newIndex);
    }
}

alt text

And whole code sample:

abstract class AScreen extends MainScreen {
    boolean mMenuEnabled = false;
    SizebleVFManager mContentManager = null;
    CyclicHFManager mMenuManager = null;

    public AScreen() {
        mContentManager = new SizebleVFManager(Display.getWidth(), Display
                .getHeight(), VERTICAL_SCROLL | VERTICAL_SCROLLBAR);
        add(mContentManager);

        // mMenuManager = new CyclicHFManager(Display.getWidth(), 60);
        mMenuManager = new CyclicHFManager();
        mMenuManager.setBorder(BorderFactory.createBevelBorder(new XYEdges(4,
                0, 0, 0), new XYEdges(Color.DARKBLUE, 0, 0, 0), new XYEdges(
                Color.WHITE, 0, 0, 0)));
        mMenuManager.setBackground(BackgroundFactory
                .createLinearGradientBackground(Color.DARKBLUE, Color.DARKBLUE,
                        Color.LIGHTBLUE, Color.LIGHTBLUE));

        for (int i = 0; i < 10; i++) {
            Bitmap nBitmap = new Bitmap(60, 60);
            Graphics g = new Graphics(nBitmap);
            g.setColor(Color.DARKBLUE);
            g.fillRect(0, 0, 60, 60);
            g.setColor(Color.WHITE);
            g.drawRect(0, 0, 60, 60);
            Font f = g.getFont().derive(Font.BOLD, 40);
            g.setFont(f);
            String text = String.valueOf(i);
            g.drawText(text, (60 - f.getAdvance(text)) >> 1, (60 - f
                    .getHeight()) >> 1);

            Bitmap fBitmap = new Bitmap(60, 60);
            g = new Graphics(fBitmap);
            g.setColor(Color.DARKBLUE);
            g.fillRect(0, 0, 60, 60);
            g.setColor(Color.GOLD);
            g.drawRect(0, 0, 60, 60);
            g.setFont(f);
            g.drawText(text, (60 - f.getAdvance(text)) >> 1, (60 - f
                    .getHeight()) >> 1);

            BitmapButtonField button = new BitmapButtonField(nBitmap, fBitmap,
                    fBitmap);
            button.setCookie(String.valueOf(i));
            button.setPadding(new XYEdges(0, 18, 0, 18));

            button.setChangeListener(new FieldChangeListener() {
                public void fieldChanged(Field field, int context) {
                    Dialog.inform("Button # " + (String) field.getCookie());
                }
            });

            mMenuManager.add(button);
        }
    }

    protected boolean keyDown(int keycode, int time) {
        if (Keypad.KEY_MENU == Keypad.key(keycode)) {
            if (mMenuManager.getManager() != null) {
                delete(mMenuManager);
                mMenuManager.mCyclicTurnedOn = false;
                mContentManager.updateSize(Display.getWidth(), Display
                        .getHeight());
            } else {
                add(mMenuManager);
                mMenuManager.getField(2).setFocus();
                mMenuManager.mCyclicTurnedOn = true;
                mContentManager.updateSize(Display.getWidth(), Display
                        .getHeight()
                        - mMenuManager.getHeight());
            }
            return true;
        } else
            return super.keyDown(keycode, time);
    }
}

class FirstScreen extends AScreen {

    public FirstScreen() {
        mContentManager.add(new LabelField("This is a first screen"));
    }
}

public class ToolbarMenuApp extends UiApplication {

    public ToolbarMenuApp() {
        pushScreen(new FirstScreen());
    }

    public static void main(String[] args) {
        (new ToolbarMenuApp()).enterEventDispatcher();
    }

}
Max Gontar
Awesome answer, Max. Once again you go out of your way to post a detailed response with code. Wish I could +5 upvote this. :)
Marc Novakowski
Thanks Mark! :)
Max Gontar
I'll restart working on this project next week, but what I read and quickly tried looks great! It is very helpful, thank you!I'll still need some adjustment to do what I want (the exact same as the WeatherEye App in fact), like having the menu visible (enable) all the time, and the alert working (I have a white screen instead).I'll come back over here by next week I'm sure ahah.But again, THANK YOU!
Dachmt
You're welcome!
Max Gontar
You did that on SDK 4.6 or above right? Which SDK version did you use exactly?
Dachmt
that was bold 4.6
Max Gontar
Anyway, i will re-develop the application in 4.5 because the project is too bad and for the future it's better. For the class that is not available in 4.5, I don't think I'll need it because I'll use images and not drawing the icons, so it should be ok...but your code is very helpful, so thank you again!
Dachmt
you right, instead of Border you can use custom bitmapfield with several bitmaps (normal, focused, disabled, active) see http://stackoverflow.com/questions/1497073/blackberry-fields-layout-animation
Max Gontar
I change the code a bit to have my manager for my content manager, and then add only the menu manager.I don't want to resize my content manager, and would like to have the menu manager over the content manager instead. Do you have any idea how to do that?Thank you!
Dachmt
yes it's possible with custom layout, you can even add some animation for menu slide in/out see http://stackoverflow.com/questions/1497073/blackberry-fields-layout-animation
Max Gontar