Skip to content


BlackBerry UI - A simple custom field

I’ve covered creating your own field Manager on this site already. As you might guess, another very common part of BlackBerry UI implementation is creating your own Field class (or extending one of the built-in classes). Fortunately, the basics are very easy, even easier than creating a Manager. I’ll run through a simple from-scratch Field to illustrate everything you’ll need to know.

The field I’ll be creating is a button - now, there’s a ButtonField already in the BlackBerry UI library, but it has just enough drawbacks that I’ve implemented countless replacements. Plus, it’s a great illustrative example - a button needs to to do a bunch of things to be useful. Specifically:

  • Basic Drawing
  • Focus highlighting
  • Responding to user input (trackball and touchscreen clicks, and the enter key)
  • Firing events to listeners

Which basically covers anything you’d want to do with most fields. So let’s get started:

The CustomButtonField

We’ll call this class CustomButtonField. It will do the following things:
- Behave like a ButtonField with respect to focus and user interaction (i.e. show a different color when focused, fire an event when the user clicks on it with the trackball, touchpad, or presses the Enter key when the field is in focus)
- Allow us to easily set the text color and background color (yes you can do the background with Field.setBackground, but that’s only JDE 4.6 and later and there’s still no easy way to set the font color, which makes setting the background limited).

Constructor and instance variables

We’ll define these first, based on our requirements. We’ll of course need the label for the button, and foreground and background colors both for the focused and unfocused states.

So

private String label;
private int fontColorFocused;
private int fontColorUnfocused;
private int backgroundColorFocused;
private int backgroundColorUnfocused;

We’ll define constructors accordingly. Take care that you provide at least one constructor that takes a long style parameter and passes that to the superclass. This will be important for some managers (like my Grid Layout Manager) that use the style mask to align your field.

Basic Drawing

There are 2 main elements to drawing a BlackBerry field:
1. Setting the field’s extent (size)
2. Painting the field’s contents

Setting the extent

The API actually guides you as to which methods to use - they’re the abstract layout and paint methods in Field. Remember that - the API is decently well designed (if not quite as well documented) so looking at what’s abstract in a super class generally tells you how you get custom behavior.

Setting the extent is done in the layout method. At layout time, this will be called by whatever manager the field is contained in, passing in the maximum available height and width for this field.

This method is simple, we just use the height of the current Font in the field (this can be set by anyone who uses this field with Field.setFont()) and use Font.getAdvance(String) to get the width of our label as rendered by the field’s font. We’ll add some padding vertically and horiztonally too, and use Math.min to make sure we don’t exceed the height and width given us by our Manager.

	protected void layout(int maxWidth, int maxHeight) {
		Font font = getFont();
		int width = font.getAdvance(label) + (horizontalPadding * 2);
		int height = font.getHeight() + (verticalPadding * 2);
		// Respect the maximum width and height available from our manager
		setExtent(Math.min(width, maxWidth), Math.min(height, maxHeight));
	}

Painting

To paint the button we’ll draw a rounded rectangle in the appropriate background color, outline it with the font color, and center the text in it. The isFocus() method tells if the field currently has the focus (careful, there are bugs with it pre-4.3, mostly with Managers). Very straightforward:

	protected void paint(Graphics graphics) {
		// Draw background
		graphics.setColor(isFocus() ? backgroundColorFocused : backgroundColorUnfocused);
		graphics.fillRoundRect(0, 0, getWidth(), getHeight(), 10, 10);

		// Draw text
		graphics.setColor(isFocus() ? textColorFocused : textColorUnfocused);
		graphics.drawRoundRect(0, 0, getWidth(), getHeight(), 10, 10);
		int fontWidth = getFont().getAdvance(label);
		graphics.drawText(label, (getWidth()-fontWidth)/2, verticalPadding);
	}

Focus highlighting

Now we have a button, but if you run this code, you won’t be able to select it - it’ll just sit there drawn in its unfocused color. To make the field focusable, we override isFocusable() and return true:

	public boolean isFocusable() {
		return true;
	}

There are a couple more things we need to do. First, the BlackBerry UI draws an inverted rectangle for each focused field. Since our button is a rounded rectangle, and since we’re doing custom coloring, we don’t want that to happen, so we just override drawFocus to do nothing:

	protected void drawFocus(Graphics graphics, boolean on) {
		// Don't draw the default focus
	}

Finally since we’ve done this we’ve interrupted the normal times when the focus is painted and unpainted. Our field needs to know to repaint when the focus changed, so we override onFocus and onUnfocus to invalidate the field after setting the focus (by calling the same methods on Field):

	protected void onFocus(int direction) {
		super.onFocus(direction);
		invalidate();
	}

	protected void onUnfocus() {
		super.onUnfocus();
		invalidate();
	}

Running this code we have fields that look like buttons that change color when highlighted. Now we want them to do something.

Responding to user input and firing events

The ButtonField class notifies its FieldChangeListener whenever the user click the trackball, presses Enter, or (in the Storm) clicks the screen on top of the button. Thankfully the first and third cases are both mapped to the navigationClick method, so we just have to override that, and keyChar to capture the Enter key. In each case we simply call fieldChangeNotify - everything else (setting the listener, etc) is handled by Field already!

	protected boolean keyChar(char character, int status, int time) {
		if (character == Keypad.KEY_ENTER) {
			fieldChangeNotify(0);
			return true;
		}
		return super.keyChar(character, status, time);
	}

	protected boolean navigationClick(int status, int time) {
		fieldChangeNotify(0);
		return true;
	}

Notice fieldChangeNotify takes an int parameter - this is a way to pass some additional info about the change itself to any listener. In the case of a button it probably doesn’t make any difference if it was pressed via trackball, enter, or whatever, so we just pass 0 in every case.

So now to get a click event we can register a listener on this field like:

  customButtonField.setChangeListener(new FieldChangeListener() {
      public void fieldChanged(Field field, int context) {
            Dialog.alert("Button clicked!");
      }
   });

And that’s it - a basic custom button field. This is about as simple as a field gets (at least, one that handles focus and user input), but the building blocks are the same no matter how complex you get.

A simple example of CustomButtonField in action (using my GridFieldManager to lay a bunch of them out in appropriately gaudy colors):

CustomButtonField colors

You can download the full source for the CustomButtonField class here.

Share and Enjoy:
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google

Posted in basics, components, ui. Tagged with , , , , , .

6 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Andrew said

    Hello, is it possible for you to put up the main classes? Like to call the CustomButtonField how would i do so?
    Thanks

  2. PraveenGoparaju said

    Thanks for the detailed example. this sample helped me in implementing my own custom field. i suggest this is one of the very good examples to start with custom fields.

    goodluck

  3. rajkumar said

    Nice artical for Blackberry Custom UI

  4. Seppl said

    Very good article on the subject but it should mention that the custom field gets marked as dirty by fieldChangeNotify(0). As a consequence the user gets asked whether to save changes when the screen terminates. Overriding isDirty() and isMuddy() and returning false solves the problem (but I’m a noob and there may be better solutions).

  5. Ramya K said

    Thanks for the v nice article. I’ve just started programming for BB. Is there a possibility to add our custom buttons to a Dialog? I want to basically replace the default buttons with a background of my own.

    Any help?

Continuing the Discussion

  1. Planet Android » Blog Archive » Some Useful BlackBerry development tutorials and Custom UI components linked to this post on April 17, 2010

    [...] Creating a custom Field Custom TextBox for BlackBerry Great tutorial on custom field and GridLayoutManager [...]

Some HTML is OK

(required)

(required, but never shared)

or, reply to this post via trackback.