dcsimg

Exploring the ListField, Part 2

Subclassing for fun and function.

Subclassing

In our last article on the BlackBerry ListField we learned how to display data in a vertically oriented list.

We explored drawing text and even how to search for entries with a progressive text search.

However, the UI was somewhat bland. This article extends the prior code to upgrade the UI a bit. Along the way we demonstrate a technique for subclassing the ListField to bring some more life to the application and importantly to move in the direction of building more custom functionality to help your applications stand apart from the crowd.

Programmers familiar with object oriented languages such as Java, Objective-C, C++, Smalltalk, and others know that being comfortable with subclassing is a key technique to getting your applications to deliver the functionality you want and provide that something “extra” we desire out of our applications. It is kind of like having your kid at the science fair demonstrating along side the others. They all had access to the same materials and were given the same assignment to build a volcano, but then your kid went a step further and made the lava coming out of the volcano not only red and gooey, but hot and so life-like that someone pulled the fire alarm in terror. OK, so maybe that is a little over the top, but that is what we’re after — something in our applications that delivers more than the “out of the box” variety experience.

Some might say, then why are you messing with BlackBerry? Good question — I have faith that RIM is not going to roll over and issue iPhones to their staff. If they do, I’ll be the first to admit I was wrong and purchase yet another device myself. Now, let’s see what we can do to add some more spice to our ListField-based BlackBerry Application.

Some more color

In an earlier article we looked at changing the color of a BlackBerry screen by subclassing the VerticalFieldManager. This article demonstrates adding color to the BlackBerry ListField.

Some of the behavior is modified via a subclassed class named ColorList, while the primary modifications are made within the drawListRow() method of the ListFieldCallback implementation.

Before we get into the specifics of subclassing the ColorField, let’s add some functionality to the application using the stock ListField.

Here is the code for the main UI screen, BBColorScreen:

/*
 * BBColorScreen.java
 */

package com.msi.linuxmag.cl;

import net.rim.device.api.ui.*;
import net.rim.device.api.system.*;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.ButtonField;

import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.component.ListField;
import net.rim.device.api.ui.component.ListFieldCallback;

class BBColorScreen extends MainScreen implements ListFieldCallback,FieldChangeListener{
    ColorList sampleList;
    int currentColorIndex = 0;
    ButtonField changeColorButton;
    String [] listData = {"ALICEBLUE","ANTIQUEWHITE","AQUA","AQUAMARINE","AZURE",
"BEIGE","BISQUE","BLACK","BLANCHEDIAMOND"};
    int [] colorData = {Color.ALICEBLUE,Color.ANTIQUEWHITE,Color.AQUA,Color.AQUAMARINE,
Color.AZURE,Color.BEIGE,Color.BISQUE,Color.BLACK,Color.BLANCHEDALMOND};

    BBColorScreen() {
        super(DEFAULT_MENU);
        changeColorButton = new ButtonField("Change colors",
ButtonField.CONSUME_CLICK | ButtonField.NEVER_DIRTY);
        changeColorButton.setChangeListener(this);
        add(changeColorButton);
        add(new SeparatorField());
        sampleList = new ColorList();
        sampleList.setSize(listData.length);
        sampleList.setCallback(this);
        add(sampleList);
        setTitle(new LabelField("Linux Mag ListField",LabelField.USE_ALL_WIDTH | DrawStyle.HCENTER));
    }
 /*
    protected void applyTheme() {
        System.out.println("applyTheme ... skeaky bugger");
    }
   */
    private int makeRGB(int r,int g,int b) {
        return (r << 16) + (g << 8) + b;
    }

    public void fieldChanged(Field f, int context)
    {
        if (f == changeColorButton) {
            currentColorIndex++;
            if (currentColorIndex >= colorData.length) currentColorIndex = 0;
            sampleList.invalidate();
        }
    }

    /* ListFieldCallback Interface methods    */
    public void drawListRow(ListField listField,Graphics graphics,int index,int y,int width)
    {
        graphics.setFont(Font.getDefault());
        graphics.setColor(colorData[currentColorIndex]);
        graphics.fillRect(0,listField.getRowHeight() * index,Display.getWidth(),listField.getRowHeight());
        graphics.setColor(Color.BLACK);
        graphics.drawText(listData[index],2,y,DrawStyle.TOP,width);
    }

    public int getPreferredWidth(ListField listField)
    {
        return Display.getWidth();
    }
    public Object get(ListField listField,int index)
    {
        return listData[index];
    }

    public int indexOfList(ListField listField,String prefix,int start)
    {
        try {
            int ret = -1;
            for (ret = start;ret<listField.getSize();ret++) {
                if (listData[ret].toUpperCase().startsWith(prefix.toUpperCase())) return ret;
            }
            return 0;
        } catch (Exception e) {
            return 0;
        }
    }
/* End of ListFieldCallback Interface methods */

}

This user interface consists of three fields: a ButtonField (changeColorButton), a SeparatorField, and a ListField (sampleList).

New UI with ButtonField, SeparatorField, and ListField
New UI with ButtonField, SeparatorField, and ListField

This class implements not only the ListFieldCallback but also the FieldChangeListener interface to handle Button presses. In addition to the array of Strings, this class has an array of integers holding Color values. Each time the user presses the changeColorButton the class level variable currentColorIndex is incremented through the range of available color values stored in the colorData array. Then we request the ListField to redraw by calling its invalidate() method.

    public void fieldChanged(Field f, int context)
    {
        if (f == changeColorButton) {
            currentColorIndex++;
            if (currentColorIndex >= colorData.length) currentColorIndex = 0;
            sampleList.invalidate();
        }
    }

Now, with some color!
Now, with some color!

As the user selects the changeColorButton, the display updates with each successive color used as the background. In order to draw this background we have to perform a little bit of work by actually painting it with the graphics.fillRect() method:

    public void drawListRow(ListField listField,Graphics graphics,int index,int y,int width)
    {
        ....
        graphics.setColor(colorData[currentColorIndex]);
        graphics.fillRect(0,listField.getRowHeight() * index,Display.getWidth(),listField.getRowHeight());
        ....
    }

Note how we use the listField’s row height to calculate the dimensions of the rectangle to draw. Now we can cycle through the colors quite happily, however, we’re missing something — the focus rectangle. That’s right, we don’t know which row is selected! How do we fix that?

Uhoh, where's the selection?!
Uhoh, where’s the selection?!

Enter subclassing. We subclass the ListField in order to override the drawFocus() method.

/*
 * ColorList.java
 */

package com.msi.linuxmag.cl;

import net.rim.device.api.ui.*;
import net.rim.device.api.system.*;
import net.rim.device.api.ui.component.ListField;
import net.rim.device.api.ui.component.ListFieldCallback;

class ColorList extends ListField{
    ColorList() {
        super();
    }

    protected void drawFocus(Graphics g,boolean on) {
        g.invert(g.getClippingRect());
    }
}

We could of course override more methods and anyone doing some serious BlackBerry programming will likely wind up down that road before long. In this example, we demonstrate overriding only the drawFocus() method where we invert the currently “selected” area, otherwise known as the clipping rectangle.

In order to use this new class, revisit the code and replace the instances of ListField with ColorList:

ColorList sampleList;

    BBColorScreen() {
        super(DEFAULT_MENU);
        ...
        sampleList = new ColorList();
        ...
    }

Now, when we search for an entry and it is selected, we can actually see it! What is particularly interesting is that we get a more pleasant experience by asking the display to invert the colors rather than picking a hard-coded color for the focus.

That's better, Inverted row shows selection.
That’s better, Inverted row shows selection.

OK, so that’s cool, we have some color. But what about something a little bit more interesting? Let’s say we want to display an image behind our list’s entries. We can do that too!

We can add a background image incrementally by drawing a “slice” of a Bitmap instead of a background color.

    Bitmap backgroundImage;

    BBColorScreen() {
        ...
        backgroundImage = Bitmap.getBitmapResource("lmlogo.jpg");
        ...
    }

    public void drawListRow(ListField listField,Graphics graphics,int index,int y,int width)
    {
        XYRect rect = new XYRect(0,y,Math.min(Display.getWidth(),this.backgroundImage.getWidth()),Math.min(listField.getRowHeight(),this.backgroundImage.getHeight()));
        graphics.drawBitmap(rect,this.backgroundImage,0,y % this.backgroundImage.getHeight());
        graphics.setFont(Font.getDefault());
    //    graphics.setColor(colorData[currentColorIndex]);
    //    graphics.fillRect(0,listField.getRowHeight() * index,Display.getWidth(),listField.getRowHeight());
        graphics.setColor(Color.BLACK);
        graphics.drawText(listData[index],2,y,DrawStyle.TOP,width);
    }

Now with background image.  But too dark!
Now with background image. But too dark!

We accomplish this by first calculating each list’s rectangle (XYRect in the code) and then painting the Bitmap into that rectangle. Note that in the constructor, we load the Bitmap via the Bitmap.getBitmapResource(filename) method.

So far so good. Oh wait, we cannot see the list entries with the graphic so dark. Let’s have a look at thinning out the background through the use of the alpha channel.

    public void drawListRow(ListField listField,Graphics graphics,int index,int y,int width)
    {
        int saveAlpha = graphics.getGlobalAlpha();
        graphics.setGlobalAlpha(64);

        XYRect rect = new XYRect(0,y,Math.min(Display.getWidth(),this.backgroundImage.getWidth()),Math.min(listField.getRowHeight(),this.backgroundImage.getHeight()));
        graphics.drawBitmap(rect,this.backgroundImage,0,y % this.backgroundImage.getHeight());

        graphics.setGlobalAlpha(saveAlpha);

        graphics.setFont(Font.getDefault());
        graphics.setColor(Color.BLACK);
        graphics.drawText(listData[index],2,y,DrawStyle.TOP,width);
    }

Light backround allows list to show
Light backround allows list to show

And here it is with a selected item.

And finally, with selected entry.
And finally, with selected entry.

There is more to do to take the UI “over the top”, however we’ll have to revisit it another day. For now, hopefully you have a feel for somethings that can be done to dress up the display a bit. Next up, displaying records from a persistent store.

Comments on "Exploring the ListField, Part 2"

Chostislas

I have a problem with de ListField focus… when I navigate through the list, every option I pass through keeps on focus, I mean there are so many focused and not just one

(Sorry for my english =P)

Thanks

Reply

I really like and appreciate your article post.Thanks Again. Really Great.

Reply

It’s best to participate in a contest for one of the best blogs on the web. I’ll advocate this site!

Reply

If you wrote an article about life we’d all reach enighltenment.

Reply

More posts of this quialty. Not the usual c***, please

Reply

awful idea car insurance quotes well now time auto insurance quotes companies continues need car insurance liability system find affordable car insurance foolish driving class auto insurance firm vehicles

Reply

probably car insurance cheap keep protected cheap car insurance doing pay cheap car insurance quotes household loan biting cheap car insurance saving non-insured car insurance quotes online insurance action such car insurance online bags gracefully car insurance rates any old compare auto auto insurance quotes insurance

Reply

some minimum auto insurance quotes been driving cheap auto insurance daunting task particular industry cheapest auto insurance automobile insurance concerned cheap auto insurance maintain any reimbursement auto insurance quote insurance company takes automobile insurance companies voice online car insurance yourself customer auto insurance quote great deals

Reply

locating car insurance car accidents given huge car insurance quote collection art same cheap car insurance healthcare stolen auto insurance quote many complexities employee online car insurance unsafe past additional ways car insurance online debts how much car insurance quotes someone else

Reply

insurances car insurance online broken into easily cheap auto insurance essential possessions learning car insurance more drivers commonly known insurance car sufficient

Reply

grasp auto insurance quote make sure companies auto insurance quotes companies vehicle car insurance quotes big help without compromising auto insurance driver license insurance auto insurance quotes many helpful dui cheap auto insurance drive lowest rate auto insurance quotes provide free vehicle car insurance quotes replacement

Reply

insurance cheapest auto insurance larger package discounts cheapest car insurance being rented eighth car insurance quote only device does insurance quotes auto many start now cheap auto insurance than men record insurance quotes auto policy types

Reply

danger financially insurance auto quote accident how still pay car insurance where worker comparatively lightweight car insurance quotes dangerous definitely go car insurance getting asda insurance cheap insurance quotes varied agencies way though auto insurance maintaining violations car insurance rates current home result online auto insurance after passing

Reply

about areas cheap car insurance quotes someone who contacting car online car insurance damage natural hyped car insurance quotes online driving record

Reply

due cheap car insurance protected towing process auto insurance quote new share programs quote auto insurance theft burglary

Reply