Wednesday, July 7, 2010

Blackberry UI, What's on the Menu

Creative Commons Licence
This work is licenced under a Creative Commons Licence.

Often one of the first things we want to do is add a menu to our Screen. The MainScreen we learned of last time makes this quite easy but also flexible. First as always we need to import the new Classes we are going to use:

import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.ContextMenu;
import net.rim.device.api.ui.component.Menu;

To post a menu we over ride the base Class (MainScreen in this case) implementation of makeMenu(). Since, for the moment at least, we are only providing a single menu we can ignore instance.

First we find out which Field, if any, has focus. We can then get the contextMenu for that Field, if any, and include it in our menu. The context menu contains items like Copy and Paste or other actions that make sense in the context of the Field with focus.

In many programs and tutorials you will find line 47 written using the UiApplication Class:

Field focus = UiApplication.getUiApplication().getActiveScreen().getLeafFieldWithFocus();

This is of course perfectly good coding, arguable better than what I've done here. The way I've coded it demonstrates that our main Class BasicGUI is a sub-Class of UiApplication so we can use it anyplace we would use UiApplication. This saves us from having to import the definition of UiApplication into the BasicGUIScreen file because the definition of BasicGUI is autmatically shared with all classes in the package src.lessonOn. So why is using UiApplication better? Well, if we decide we want to use BasicGUIScreen in an application with a different main Class that isn't named BasicGUI, we will have a problem. Something to keep in mind.

With the potential context menu taken care of we can add our own MenuItem screen2 which we will define in a moment. Finally if we want to include the default menu items, Close and Switch Application we simply call the Super Class implementation of makeMenu(). If we leave that call out, then we can eliminate those options from the menu, if we so chose.

protected void makeMenu(Menu menu, int instance) {

 Field focus = BasicGUI.getUiApplication().getActiveScreen().getLeafFieldWithFocus();
 if (focus != null) {
  ContextMenu context = focus.getContextMenu();
  if (!context.isEmpty()) {
   menu.add(context);
   menu.addSeparator();
  }
 }

 menu.add(screen2);

 super.makeMenu(menu, instance);
}

One way to create a MenuItem is as an instance variable. This is no different than declaring and initializing a simple type, like an int, but a bit more complex because a MenuItem is a complex type. The three arguments to the MenuItem constructor are: the text to display in the menu; the ordinal, which is used to sort the MenuItems on the menu; and the priority which is used to dynamically select the MenuItem that is selected when the menu is first posted. When the MenuItem is selected, the run() method is executed on the Event Thread. So you must remember the priviledges and restrictions that go along with running on the Event Thread: no long processing, but you may alter the UI. In this case we create an instance of MainScreen, set the title and add a LabelField, and finally push the Screen onto the screen stack.

private MenuItem screen2 = new MenuItem("Screen 2", 200, 200) {
 public void run() {
  MainScreen s2 = new MainScreen();
  s2.setTitle("Screen 2");
  s2.add(new LabelField("This is screen number 2"));
  BasicGUI.getUiApplication().pushScreen(s2);
 }
};

And here is the new BasicGUIScreen.java source file:

/*
* BasicGUIScreen.java
*
* © Richard Buckley www.hrbuckley.net, 2010
* 
* This work is licenced under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
* To view a copy of this licence, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
* Creative Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA.
*/

package src.lessonOne;

import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.ContextMenu;
import net.rim.device.api.ui.component.Menu;

//
//
//
public class BasicGUIScreen extends MainScreen {
 BasicGUIScreen() {
  setTitle("Hello World");
  add(new LabelField("Hello World"));
 }

 private MenuItem screen2 = new MenuItem("Screen 2", 200, 200) {
  public void run() {
   MainScreen s2 = new MainScreen();
   s2.setTitle("Screen 2");
   s2.add(new LabelField("This is screen number 2"));
   BasicGUI.getUiApplication().pushScreen(s2);
  }
 };

 //
 // Populate the screen menu
 // @param menu the menu to populate
 // @param instance the instance, allows different menus to be posted depending
 // on user interaction. It will be 0 if the menu is posted by pressing the BB 
 // button, non-zero if it was posted by a trackball click.
 //
 protected void makeMenu(Menu menu, int instance) {

  Field focus = BasicGUI.getUiApplication().getActiveScreen().getLeafFieldWithFocus();
  if (focus != null) {
   ContextMenu context = focus.getContextMenu();
   if (!context.isEmpty()) {
    menu.add(context);
    menu.addSeparator();
   }
  }

  menu.add(screen2);

  super.makeMenu(menu, instance);
 }
} 

We could have created this screen in a number of ways. The most flexible would have been to create a new sub-Class of MainScreen. We could also reuse BasicGUIScreen. Similarly the MenuItem could be created when makeMenu is run if and when it is needed rather that when BasicGUIScreen is instantiated as screen2 is:

menu.add(new MenuItem("Screen 3", 200, 300) {
 public void run() {
  BasicGUIScreen bgs = new BasicGUIScreen();
  bgs.setTitle("Screen 3");
  BasicGUI.getUiApplication().pushScreen(bgs);
 }
});

Java allows all kinds of shortcuts like this. Sometimes they are very handy and improve readability, sometimes not.

As always, the Blackberry JDE project files are available from the Lesson1 Git repository. Enjoy.


1 comment:

  1. Thank you, very helpful explanation for us starting out.

    ReplyDelete