TextBoxField revisited

by Developer on ‎07-29-2010 12:20 PM - edited on ‎09-20-2010 05:01 PM by Retired (11,940 Views)

Introduction

 

This article was written as a follow-up to an old article in the BlackBerry® developers journal.  I decided to retain the old class name so that people getting advice from someone remembering the old one will be able to find this.  I have fixed some problems with that code as well.

  

Problem Definition

 

These days, wherever you look, there are input forms.  Many fields in those forms are multi-line text entry boxes.

(Another common element is a one-line entry field either limited in size such as a phone number or horizontally scrollable to accommodate longer inputs such as a street address or an e-mail subject line.  I have addressed the latter in another article - "Sample code - scrollable one-line text input field")

 

Those multi-line text entry boxes are already quite standard.  Most of them:

 

  1. Have well-defined size
  2. Have some border around them
  3. Word-wrap at the right boundary
  4. Scroll vertically to enable navigating back and forth through a long text

If we look at text entry classes on BlackBerry devices (my personal favorite is EditField, though even TextField is advanced enough) we will see that they already provide word wrap.  We just need to add the other three features.  Let's think how we achieve that.

 

Analysis

 

  • Well-defined size
We need some way of specifying the width and height of the field.  I prefer doing that in the constructor, just like you specify style bit such as USE_ALL_WIDTH or FIELD_HCENTER in the constructor of the built-in classes.  Thus, we need a constructor which will accept the desired width and height

  • Border
For those fortunate enough who have to support only newer phones with net.rim.device.api.ui.decor package, this part is extremely easy.  At my work, I still have to support BlackBerry® Device Software 4.2.1; thus I will write somewhat lower-level code.  Don't worry - it's only a few lines.  Graphics.drawRect() to the rescue!

  • Vertical Scroll
That's easy: VerticalFieldManager(VERTICAL_SCROLL) is the universally accepted tool to achieve exactly that.

 

Solution

 

Let me show you the code and explain the key points:

 

public	class TextBoxField extends Manager {
    int managerWidth;
    int managerHeight;

    private VerticalFieldManager vfm = new VerticalFieldManager(VERTICAL_SCROLL | VERTICAL_SCROLLBAR | USE_ALL_WIDTH | USE_ALL_HEIGHT);
    private EditField editField = new EditField("", "", EditField.DEFAULT_MAXCHARS, FOCUSABLE);

    TextBoxField(int width, int height, long style) {
        super(style | NO_VERTICAL_SCROLL | NO_HORIZONTAL_SCROLL);
	managerWidth = width;
	managerHeight = height;
		
	add(vfm);
	vfm.add(editField);
    }

    TextBoxField(int width, int height) {
        this(width, height, 0L);
    }
		
    public String getText() {
	return editField.getText();
    }

    public int getPreferredWidth() {
        return managerWidth;
    }

    public int getPreferredHeight() {
        return managerHeight;
    }
		
    protected void sublayout(int w, int h) {
        if (managerWidth == 0) {
            managerWidth = w;
        }
        if (managerHeight == 0) {
            managerHeight = h;
        }
	int actWidth = Math.min(managerWidth, w);
	int actHeight = Math.min(managerHeight, h);
	layoutChild(vfm, actWidth - 2, actHeight - 2); // Leave room for border
	setPositionChild(vfm, 1, 1);	              // again, careful not to stomp over the border
        setExtent(actWidth, actHeight);
    }
		
    protected void paint(Graphics g) {
	super.paint(g);
	int prevColor = g.getColor();
	g.setColor(Color.BLACK);
	g.drawRect(0, 0, getWidth(), getHeight());  // draws border
	g.setColor(prevColor);
    }
}

1. extends Manager (rather than VerticalFieldManager):

    we don't need a specialized container such as a VerticalFieldManager.  We provide sublayout ourselves, as well as getPreferredWidth / getPreferredHeight.

 

2. USE_ALL_WIDTH | USE_ALL_HEIGHT:
    This is my personal preference, but I think the inner (scrolling) Manager should use all the width and height you give it.  If you ever start beautifying this gadget with various background colors and so on, it will feel weird when the field is still short.

 

3. Use of Math.min to determine your Field's actual size:

    sublayout's parameters - w and h - tell you your Field's maximum available visual area.  Honor those maximums!

 

4. Making room for the border:

    we lay out our inner VerticalFieldManager with smaller values than we use for the whole field (notice those "-2" in layoutChild call).  This is because we reserve 2 pixels (1 on each side) for the border.  We also position it (notice setPositionChild call) with the same restrictions in mind.

 

5. Saving and restoring your Graphics color (holds true for background color as well when you use one):

    You want something of a specific color?  Fine - but don't forget to change that color back to its original value once you're done using it.  Otherwise you might see all kinds of graphical artifacts which will be difficult to explain!

 

I hope this little piece of code is useful for you.