5

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 http://www.blackberrybing.com/resource/pics/201002/WeatherEye-OS-45.jpg

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

Maksym Gontar
  • 22,765
  • 10
  • 78
  • 114
Dachmt
  • 2,079
  • 4
  • 29
  • 45

1 Answers1

10

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 http://img109.imageshack.us/img109/6176/toolbarj.jpg

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();
    }

}
Community
  • 1
  • 1
Maksym Gontar
  • 22,765
  • 10
  • 78
  • 114
  • 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 Apr 18 '10 at 00:19
  • 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 Apr 29 '10 at 03:09
  • You did that on SDK 4.6 or above right? Which SDK version did you use exactly? – Dachmt May 05 '10 at 00:33
  • 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 May 10 '10 at 16:04
  • 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 – Maksym Gontar May 10 '10 at 17:43
  • 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 Jun 02 '10 at 00:17
  • 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 – Maksym Gontar Jun 02 '10 at 07:55