Welcome!

Welcome to the official BlackBerry Support Community Forums.

This is your resource to discuss support topics with your peers, and learn from each other.

inside custom component

Java Development

TextBoxField revisited

by Developer on ‎07-29-2010 12:20 PM - edited on ‎09-20-2010 05:01 PM by BlackBerry Development Advisor (11,627 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.  

Comments
by Developer on ‎08-09-2010 10:27 AM

I suggested this article to some people in the support forums.  One of the uses I didn't anticipate was to have a scrollable read-only programmatically changeable field (think event log or a chat window).  There needs to be a possibility to make the field READONLY or even NON_FOCUSABLE, as well as the ability to setText or append some text.  Here is a possible  TextBoxField(int, int, long) constructor change (we then don't create the editField until we get to this constructor and determine what style does it need to have):

    TextBoxField(int width, int height, long style) {
        super(style | NO_VERTICAL_SCROLL | NO_HORIZONTAL_SCROLL);
        long innerStyle = style & (READONLY | FOCUSABLE_MASK); // at least
	managerWidth = width;
	managerHeight = height;
        editField = new EditField("", "", EditField.DEFAULT_MAXCHARS, innerStyle);
		
	add(vfm);
	vfm.add(editField);
    }

setText and append might look like this:

public void append(String addedText) {
  String newText = editField.getText() + addedText;
  editField.setText(newText);
  editField.setCursorPosition(newText.length());
}

public void setText(String newText) {
  editField.setText(newText);
}

See that "setCursorPosition"?  This is a matter of style, but I have a feeling that after adding a text (like sending a new chat message) the user would expect to see that part of text on the screen immediately, not after stepping in there and scrolling down.

by Developer on ‎08-20-2010 05:51 PM

After some pondering I found how to properly change the border color on focus changes (there was such a question in the forums).  Unfortunately, onUnfocus() on editField doesn't work - somehow a field is never aware of it losing focus if the focus shifts outside of its Manager.

 

The solution would be to:

1) Declare that this class implements FocusChangeListener :

public	class TextBoxField extends Manager implements FocusChangeListener {

 

 

2) set this as a focus change listener on editField - like this:

    editField.setFocusListener(this);

 

3) add some member called, say, borderColor, and set the color to that value instead of Color.BLACK before drawRect() inside paint().  Initialize to unfocused state.  I used Color.BLUE for unfocused and Color.RED for focused

 

4) implement focusChanged to change that color and cause a repaint:

	public void focusChanged(Field field, int eventType) {
		if (field == editField) {
			switch (eventType) {
			case FOCUS_GAINED:
				borderColor = Color.RED;
				invalidate();
				break;
			case FOCUS_LOST:
				borderColor = Color.BLUE;
				invalidate();
				break;
			default:
				break;
			}
		}
		
	}

Well, you get the idea.  Nothing special, but might be nice at times.

by Developer on ‎10-03-2011 02:09 PM

I'm having difficulty is making the Vertical Scroll bar arrows visible when using this code. Any idea why the up and down arrow are not visible in this code? Yes, I've modified the code a bit but not getting a reason why it is not working. May I request you to put some screenshot of how originially it looks at your end when you coded it?

 

Thanks,

sameer