Thursday, April 23, 2009

Code : Create your own VirtualKeyboard for BBStorm

Problem :

Code using component pack 4.7.0.39 and the Storm simulator 2.11.0.72. I have created an EditField with the FILTER_REAL_NUMERIC flag (and no other flags) and when the field has focus the virtual keyboard pops up as expected but it is missing the number '1'. I didn't add any other filters to the field.

Missing number 1

I have another EditField using the FILTER_NUMERIC flag instead, and it works fine. It seems that for real numbers it just replaces the '1' with the '.' key and leaves no way to insert that number, and if i tilt the simulator sideways the full keyboard is shown and this one has all the numbers.

Solution :

Well I have finally resolved this by developing my own home grown virtual keyboard.  This should work until RIM fixes the bug with their virtual keyboard.  In case anyone else is having the same problem, I have provide the code for it here:

 

public class MyVirtualKeyboard extends VerticalFieldManager
{
    // 1---2---3
    // 4---5---6
    // 7---8---9
    // .---0---c
    private ButtonField[] numbers = new ButtonField[]
    {
        new ButtonField("1", ButtonField.CONSUME_CLICK),
        new ButtonField("2", ButtonField.CONSUME_CLICK),
        new ButtonField("3", ButtonField.CONSUME_CLICK),
        new ButtonField("4", ButtonField.CONSUME_CLICK),
        new ButtonField("5", ButtonField.CONSUME_CLICK),
        new ButtonField("6", ButtonField.CONSUME_CLICK),
        new ButtonField("7", ButtonField.CONSUME_CLICK),
        new ButtonField("8", ButtonField.CONSUME_CLICK),
        new ButtonField("9", ButtonField.CONSUME_CLICK),
        new ButtonField(".", ButtonField.CONSUME_CLICK),
        new ButtonField("0", ButtonField.CONSUME_CLICK),
        new ButtonField("c", ButtonField.CONSUME_CLICK),
    };
    private ButtonField close = new ButtonField("Close",
        ButtonField.CONSUME_CLICK);
    private FieldChangeListener listener = new FieldChangeListener()
    {
        public void fieldChanged(Field f, int ctx)
        {
            if (ctx == FieldChangeListener.PROGRAMMATIC)
                return;
            String val = ((ButtonField) f).getLabel();
            if (Character.isDigit(val.charAt(0)) || val.equals("."))
                caller.setCharacter(val);
            else if (val.equals("c"))
                caller.removeLastCharacter();
        }
    };
    private Caller caller;
    public MyVirtualKeyboard(Caller caller)
    {
        this.caller = caller;
        // 4 rows of buttons will be displayed
        int buttonIndex = 0;
        for (int i = 0; i < 4; i++)
        {
            HorizontalFieldManager row = new HorizontalFieldManager();
            for (int j = 0; j < 3; j++)
            {
                numbers[buttonIndex].setChangeListener(listener);
                row.add(numbers[buttonIndex++]);
            }
            add(row);
        }
        close.setChangeListener(new FieldChangeListener()
        {
            public void fieldChanged(Field field, int ctx)
            {
                MyVirtualKeyboard.this.caller.closeMe();
            }
        });
        add(close);
    }
}

Here is the interface I created callled 'Caller':

public interface Caller
{
    public void closeMe();
    public void setCharacter(String character);
    public void removeLastCharacter();
}

 

Here is how I invoke it (this code is in my MainScreen subclass, which is implementing FocusChangeListener and my call back interface Caller):

public void focusChanged(Field field, int ctx)    {
        currentlyEditing = null;
        if (field != checkAmt && field != taxAmt)
            return;
        if (ctx == FocusChangeListener.FOCUS_GAINED)
        {
            currentlyEditing = (BasicEditField) field;
            MyVirtualKeyboard keyboard = new MyVirtualKeyboard(this);
            popup = new PopupScreen(keyboard);
            getUiEngine().pushScreen(popup);
        }
    }

Here is the callback methods on the main screen class that take the input from the popup keyboard:

public void setCharacter(String character)
    {
        String currText = currentlyEditing.getText();
        currText += character;
        currentlyEditing.setText(currText);
    }
    public void removeLastCharacter()
    {
        String currText = currentlyEditing.getText();
        if (currText.length() == 0)
            return;
        currentlyEditing.setText(currText.substring(0, currText.length() - 1));
    }

  public void closeMe()
    {
        getUiEngine().popScreen(popup);
    }

Also, I have a menu item where if the user needs to display the keyboard, they can:

showKeyboard = new MenuItem("Show Keyboard", 3, 12)       {
            public void run()
            {
                MyVirtualKeyboard keyboard = new MyVirtualKeyboard(
                    MyScreen.this);
                popup = new PopupScreen(keyboard);
                getUiEngine().pushScreen(popup);
            }
        };

 

Enjoy!

4 comments:

  1. and how do you actually do this? i mean you do all the codes and all, but to start off with it, any hint? thanks.

    ReplyDelete
  2. Please find a sample application build on JDE 4.7 on the following link

    http://www.sendspace.com/file/o9x08l

    ReplyDelete
  3. I have the same problem with the default simulator and FILTER_REAL_NUMERIC except no virtual keyboard, it allows me to enter all the numbers and the decimal point, but when I try to enter a 1, it give me an exception error, seems the mode will allow me to enter the 1, but the filter is not looking for it, only the decimal point instead. Quite bizaar.

    ReplyDelete
  4. Nice set of tutorials. Also, find the tutorials to download image over HTTP in blackberry here.
    http://objectechenica.blogspot.com/2012/02/downloading-image-over-http-in.html

    ReplyDelete

Place your comments here...