Refreshing field's state - blackberry

In my application I'm using custom fields, with "set***" methods wich changes some parameters of this fields (background image, for example). thay work allmost fine, only one problem: I'm setting and changing parameters of this fields like below:
record = new UIButton("RECORD", Field.FOCUSABLE, kButtonWidth/3-5, kButtonHeight);
vfm2.add(Record); //I tryed this befor setters and after: no different
record.setBackgroundImage("buttonDark.png", "buttonDark.png", "buttonDark.png");
record.setTitleFontSize(Display.getHeight()/40);
record.setTitle("RECORD");
When the screen with this fields are pushed, my field looks like no setters were called (but it was: I checked this via log messages). Field's state refreshes only after it is focused (I'm calling same setters on onFocus and on onUnFocus, where I have invalidate()). Is there any way to refrash it on screen appear? In iPhone SDK, for example, there is viewDidAppear method, that colled when view(screen) did appear. Is there any same in blackberry? Or any other solution?
Here is my code of UIButton class:
public class UIButton extends Field
{
private String title = null;
private Font font;
private int fontSize;
private int color;
private int horizontalAligment;
private int state; //0 - normal; 1 - focused; 2 - HightLighted;
private int height;
private int width;
private EncodedImage currentPicture;
private EncodedImage onPicture;
private EncodedImage offPicture;
private EncodedImage lightPicture;
public UIButton(long style, int Widgh, int Height)
{
super(style);
height = Height;
width = Widgh;
fontSize = Display.getHeight()/20;
FontFamily ff = getFont().getFontFamily();
font = ff.getFont(0, fontSize);
title = "";
color = Color.WHITE;
state = 0;
horizontalAligment = DrawStyle.HCENTER;
onPicture = offPicture = lightPicture = EncodedImage.getEncodedImageResource("buttonDark.png");
currentPicture = offPicture;
}
public String getTitle()
{
return title;
}
public void setTitleColor (int Color) {
color = Color;
invalidate();
}
public void setFrame (int Height, int Width) {
height = Height;
width = Width;
invalidate();
}
public void setTitle (String Title) {
title = Title;
invalidate();
}
public void setTitleHorizontalAligment (int hAligment) {
horizontalAligment = hAligment;
invalidate();
}
public void setBackgroundImage (String forStateNurmal, String forStateFocused, String forStateHightlighted) {
onPicture = EncodedImage.getEncodedImageResource(forStateFocused);
offPicture = EncodedImage.getEncodedImageResource(forStateNurmal);
lightPicture = EncodedImage.getEncodedImageResource(forStateHightlighted);
invalidate();
}
public void setState (int State) {
state = State;
switch (state) {
case 0: {
currentPicture = offPicture;
invalidate();
break;
}
case 1: {
currentPicture = onPicture;
invalidate();
break;
}
case 2: {
currentPicture = lightPicture;
invalidate();
break;
}
}
}
public void setTitleFont (Font Font) {
font = Font;
invalidate();
}
public void setTitleFontSize (int FontSize) {
fontSize = FontSize;
FontFamily ff = font.getFontFamily();
font = ff.getFont(0, fontSize);
invalidate();
}
public int getPreferredHeight()
{
return height;
}
public int getPreferredWidth()
{
return width;
}
protected void onFocus(int direction)
{
super.onFocus(direction);
this.setState(0);
}
protected void onUnfocus()
{
if (state!=2) this.setState(1);
}
protected void drawFocus(Graphics graphics, boolean on)
{
super.drawFocus(graphics, on);
}
protected void layout(int width, int height)
{
setExtent(getPreferredWidth(),getPreferredHeight());
}
protected void paint(Graphics graphics)
{
ResizeImage r = new ResizeImage();
currentPicture = r.sizeImage(currentPicture, width-2, height-2);
graphics.drawBitmap(1, 1, width-2, height-2, currentPicture.getBitmap(), 0, 0);
if (title.getBytes().length>0) {
graphics.setColor(color);
graphics.setFont(font);
int x = 0;
if (horizontalAligment == DrawStyle.LEFT) x = 2;
graphics.drawText(title, x, (height-font.getHeight())/2,
(int)( getStyle() & DrawStyle.VCENTER & horizontalAligment | DrawStyle.HALIGN_MASK ), width );
}
}
protected boolean navigationClick(int status, int time)
{
fieldChangeNotify(1);
return true;
}
}

It is a very strong convention in Java to name local and field identifiers with lower case letters. So seeing "Record" as a local variable name is quite confusing.
Without the code for your custom field, UIButton, it is impossible to answer your question here. Built-in components for BlackBerry OS would behave correctly given this sequence of add and sets, so it is likely your custom field isn't following the BlackBerry conventions with layout and painting.

You forgot to change currentPicture in setBackgroundImage(). Try currentPicture = offPicture
or call this.setState(0) in setBackgroundImage().

If you call the set** methods before you add the field to the manager you should not have this problem in the first place. Is there a reason you call them after?

Related

Blackberry scrolling doesn't redraw fields

I have a very strange problem at the moment.
Basically when I scroll in a screen, the fields don't get redrawn completely or consistently.
I have a Screen (NO_VERTICAL_SCROLL), with a manager as a titlebar. Below that I have a vertical field manager (VERTICAL_SCROLL) with labelfields. When I scroll the vfm one or two lines of the labelfields, which were already visible, get redrawn. The section I'm scrolling down to has absolutely nothing drawn.
I tried invalidate(), and calling doPaint in a scrollchangelistener, but its actually much worse. It results in the titlebar only being partially redrawn.
In the code below I used a custom FontManager, DimenManager, and ImageResourceManager to return values dependent on screen size. I used a custom BitmapButtonField and ClickableLabel in order to change the state of a field when a click is being held in.
public class BaseScreen extends MainScreen implements StringsResource
{
protected ResourceBundle resources;
public BaseScreen(long style)
{
super(style);
StandardTitleBar titlebar = new StandardTitleBar();
titlebar.addSignalIndicator();
titlebar.addClock();
titlebar.addNotifications();
setTitle(titlebar);
resources = ResourceBundle.getBundle(BUNDLE_ID, BUNDLE_NAME);
}
}
public class TandCScreen extends BaseScreen
{
final String copy_text1 = "long text here";
final String copy_text2 = "even longer text here";
ColoredLabelField label_title;
ColoredLabelField label_subtitle;
ColoredLabelField label1;
ColoredLabelField label2;
ClickableLabel label3;
public TandCScreen()
{
super(NO_VERTICAL_SCROLL | NO_VERTICAL_SCROLLBAR);
label_title = new ColoredLabelField(resources.getString(STRING_APP_NAME), Color.WHITE, DrawStyle.HCENTER | USE_ALL_WIDTH);
label_title.setBackground(BackgroundFactory.createSolidBackground(0x60223b));
label_subtitle = new ColoredLabelField(resources.getString(STRING_TANDC_TITLE), 0x58585b, DrawStyle.HCENTER | USE_ALL_WIDTH);
label1 = new ColoredLabelField(copy_text1, 0x58585b, USE_ALL_WIDTH);
label2 = new ColoredLabelField("", 0xa7a9ab, USE_ALL_WIDTH);
label3 = new ClickableLabel("Read more...")
{
protected void unclick()
{
super.unclick();
UiApplication.getUiApplication().invokeLater(new Runnable()
{
public void run()
{
ColoredLabelField label = new ColoredLabelField(copy_text2, 0xa7a9ab, 0);
label.setFont(FontManager.body());
label.setMargin(0, 0, DimenManager.interField(), 0);
label2.getManager().replace(label2, label);
label3.getManager().delete(label3);
}
});
}
};
label_title.setFont(FontManager.subtitle());
label_subtitle.setFont(FontManager.subtitle());
label1.setFont(FontManager.body());
label2.setFont(FontManager.body());
label3.setFont(FontManager.body());
BitmapButtonField button_accept = new BitmapButtonField(ImageResourceManager.buttonAccept(), ImageResourceManager.buttonAcceptHover(), FIELD_HCENTER)
{
protected void click()
{
super.click();
setImage(ImageResourceManager.buttonAcceptSelected());
setFocusImage(ImageResourceManager.buttonAcceptSelected());
}
protected void unclick()
{
super.unclick();
PersistentStoreManager.setTandCAccepted(true);
UiApplication.getUiApplication().pushScreen(new LoginScreen());
close();
}
};
BitmapButtonField button_decline = new BitmapButtonField(ImageResourceManager.buttonDecline(), ImageResourceManager.buttonDeclineHover(), FIELD_HCENTER)
{
protected void click()
{
super.click();
setImage(ImageResourceManager.buttonDeclineSelected());
setFocusImage(ImageResourceManager.buttonDeclineSelected());
}
protected void unclick()
{
super.unclick();
close();
}
};
int margin = (VariableManager.DISPLAY_WIDTH - button_accept.getPreferredWidth()) / 2;
// calculate where to put ellipsis
Font font = label2.getFont();
int max_length = (VariableManager.DISPLAY_WIDTH - margin * 2) * 2;
int i = copy_text2.length() - 1;
while (font.getAdvance(copy_text2.substring(0, i)) + font.getAdvance("...") >= max_length)
i--;
label2.setText(copy_text2.substring(0, i).trim() + "...");
VerticalFieldManager vfm = new VerticalFieldManager(VERTICAL_SCROLL | VERTICAL_SCROLLBAR);
vfm.add(new NullField());
vfm.add(label_subtitle);
vfm.add(new Seperator());
vfm.add(label1);
vfm.add(label2);
vfm.add(label3);
vfm.add(button_accept);
vfm.add(button_decline);
vfm.setMargin(0, margin, 0, margin);
// paddings
int padding = (DimenManager.header() - label_title.getPreferredHeight()) / 2;
label_title.setPadding(padding, 0, padding, 0);
label_subtitle.setPadding(DimenManager.interField(), 0, DimenManager.interField(), 0);
label1.setMargin(DimenManager.interField(), 0, DimenManager.interField(), 0);
label3.setMargin(DimenManager.interField(), 0, DimenManager.interField(), button_accept.getPreferredWidth() - label3.getPreferredWidth());
button_decline.setMargin(DimenManager.interField(), 0, DimenManager.interButton(), 0);
add(label_title);
add(vfm);
}
protected boolean onSavePrompt()
{
return false;
}
protected void makeMenu(Menu menu, int instance)
{
if (instance == Menu.INSTANCE_CONTEXT)
{
ContextMenu contextMenu = ContextMenu.getInstance();
contextMenu.setTarget(this);
contextMenu.clear();
this.makeContextMenu(contextMenu);
menu.deleteAll();
menu.add(contextMenu);
}
else
{
super.makeMenu(menu, instance);
}
}
protected void makeContextMenu(ContextMenu contextMenu)
{
}
/**
* Clickable labelfield which changes color on down press, and fires action
* on release. Action is canceled if touch moves outside field bounds.
*
* #author kevin
*
*/
private class ClickableLabel extends LabelField
{
private boolean canceled = true;
private boolean consumed = false;
protected boolean pressed = false;
public ClickableLabel(String label)
{
super(label, LabelField.FOCUSABLE | USE_ALL_WIDTH);
setFont(FontManager.body());
}
protected void paint(Graphics g)
{
// background
if (pressed)
{
g.setColor(0x2C1721);
}
else if (isFocus())
{
g.setColor(0x993C6B);
}
else
{
g.setColor(0x60223B);
}
int padding_y = (getPreferredHeight() - getFont().getHeight()) / 2;
int padding_x = getPaddingLeft();
g.drawText(getText(), padding_x, padding_y);
}
public int getPreferredHeight()
{
return ImageResourceManager.highlight().getHeight();
}
protected void layout(int width, int height)
{
height = getPreferredHeight();
super.layout(width, height);
setExtent(width, height);
}
// --------- Highlight selected row ---------
protected void onFocus(int direction)
{
super.onFocus(direction);
invalidate();
}
protected void onUnfocus()
{
super.onUnfocus();
invalidate();
}
// --------------------------------------------
protected void drawFocus(Graphics graphics, boolean on)
{
}
/**
* Called when trackpad pressed, or touchscreen touched
*/
protected void click()
{
pressed = true;
invalidate();
}
/**
* Called when trackpad released, or touchscreen released
*/
protected void unclick()
{
cancel();
}
protected void cancel()
{
pressed = false;
invalidate();
}
protected boolean navigationClick(int status, int time)
{
if (status != 0)
{
if (consumed)
{
consumed = false;
}
else
{
click();
}
}
return true;
}
protected boolean navigationUnclick(int status, int time)
{
if (status != 0)
{
if (consumed)
consumed = false;
else
unclick();
}
return true;
}
protected boolean touchEvent(TouchEvent message)
{
int x = message.getX(1);
int y = message.getY(1);
if (x < 0 || y < 0 || x > getExtent().width || y > getExtent().height)
{
// Outside the field
if (!canceled)
{
cancel();
}
canceled = true;
return false;
}
if (message.getEvent() == TouchEvent.UP)
{
if (canceled)
cancel();
else
unclick();
consumed = true;
return true;
}
if (message.getEvent() == TouchEvent.DOWN)
{
click();
consumed = true;
canceled = false;
return true;
}
return super.touchEvent(message);
}
}
private class Seperator extends SeparatorField
{
protected void paint(Graphics graphics)
{
graphics.setColor(0xa7a9ab);
super.paint(graphics);
}
}
}
Thanks in advance for any suggestions
I don't think it is possible to do anything but guess at your problem without looking at your code. But whatever your problem is, I am confident that it is based on a misunderstanding of how to use Managers within a Screen. So I recommend that you review the following articles to improve your knowledge in this area and so hopefully resolve the problem yourself:
Start here:
UI Introduction
This provides the Background around Managers and Fields.
Then read this article:
MainScreen Explained
I suspect as a result of reading this article, you may be able to discard your 'title bar' and use setTitle() or setBanner() to provide this function.
I hope this resolves your problems.
A few other points:
In all my years of BB programming, I have never had to use doPaint() to get something painting the way I wanted. I can't think of a situation that this will in fact help. So if you think you need it, try invalidate() instead.
I have used invalidate() when I making a change to the Field that will change its on screen appearance (but not its size). I have used it in a scroll change listener. But it is a method of last resort.
Remember that LabelFields are not focusable, so in OS's before 6, that made them a problem to scroll.
Found the issue. On the labelfields, there was a setExtent(getPreferredWidth(), getPreferredHeight()); that was reducing the size of the area to redraw. Very stupid mistake.
Thanks to everyone who tried to help.

Custom layout in blackberry

I need a custom layout as below in BlackBerry.
I did same layout in Android. Now I need same layout in BlackBerry. I am new to BlackBerryapp development. The Fields of BlackBerry like Views in Android seem to be very confusing things to me.
I tried with VerticalFieldManager & HorizontalFieldManager by mixing these with BitmapField & LabelField to produce my layout.
I failed particularly in placing LabelField at bottom of screen. I used USE_ALL_HEIGHT & FIELD_BOTTOM style to put at bottom, but it is showing after scrolling long time.
My requirement is the header and footer should not scroll when my middle list is scrolling.
The easiest way to add header and footer fields that don't scroll with the content in the middle of the screen is to use MainScreen#setBanner() and MainScreen#setStatus().Here's an example:
public class HeaderFooterListScreen extends MainScreen {
private static final int BG_COLOR = Color.BLACK;
private static final int HIGHLIGHT_COLOR = Color.BLUE;
private static final int FONT_COLOR = Color.WHITE;
private static final int ROW_HEIGHT = 60;
private Object[] _rowData;
private Field _header;
private Field _footer;
private Field _spacer;
private int _orientation;
public HeaderFooterListScreen() {
super(MainScreen.VERTICAL_SCROLL | MainScreen.VERTICAL_SCROLLBAR);
Background bg = BackgroundFactory.createSolidBackground(BG_COLOR);
setBackground(bg);
getMainManager().setBackground(bg);
// header
Bitmap headerImg = Bitmap.getBitmapResource("header.png");
_header = new BitmapField(headerImg);
setBanner(_header);
// list
_rowData = new Object[] { "row one", "row two", "row three" }; //, "row four", "row five", "row six", "row seven", "row eight", "row nine", "row ten" };
ListField list = new ListField();
int c = Color.RED;
XYEdges edgeColors = new XYEdges(c, c, c, c);
XYEdges edgeThicknesses = new XYEdges(5, 5, 5, 5);
list.setBorder(BorderFactory.createSimpleBorder(edgeThicknesses, edgeColors, Border.STYLE_SOLID));
list.setCallback(new CustomListFieldCallback());
list.setRowHeight(ROW_HEIGHT);
list.setSize(_rowData.length);
add(list);
// footer
_footer = new LabelField("Footer Showing Status As Text", Field.USE_ALL_WIDTH | DrawStyle.HCENTER) {
public void paint(Graphics g) {
// change font color
int oldColor = g.getColor();
g.setColor(FONT_COLOR);
super.paint(g);
g.setColor(oldColor);
}
};
_footer.setFont(_footer.getFont().derive(Font.PLAIN, 24));
setStatus(_footer);
}
private void centerList() {
if (_spacer != null && _spacer.getManager() != null) {
// delete the old spacer field, if there was one
delete(_spacer);
}
int listHeight = _rowData.length * ROW_HEIGHT;
int availableHeight = getHeight() - _footer.getHeight() - _header.getHeight();
if (availableHeight > listHeight) {
boolean firstRun = (_spacer == null);
// add a spacer above the list to force it down enough to be centered
final int SPACE = (availableHeight - listHeight) / 2;
_spacer = new Field() {
protected void layout(int width, int height) {
setExtent(width, SPACE);
}
protected void paint(Graphics graphics) {
}
};
insert(_spacer, 0);
if (firstRun) {
getMainManager().setVerticalScroll(0);
}
}
}
// called when device orientation changes
protected void sublayout(int width, int height) {
super.sublayout(width, height);
if (_orientation != Display.getOrientation()) {
_orientation = Display.getOrientation();
// run with invokeLater() to avoid recursive sublayout() calls
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
// TODO: may have to adjust header, too?
centerList();
}
});
}
}
private class CustomListFieldCallback implements ListFieldCallback {
private final int PAD = 10;
public void drawListRow(ListField listField, Graphics graphics,
int index, int y, int width) {
int oldColor = graphics.getColor();
if (listField.getSelectedIndex() == index) {
graphics.setColor(HIGHLIGHT_COLOR);
} else {
graphics.setColor(BG_COLOR);
}
graphics.fillRect(0, y, width, listField.getRowHeight());
graphics.setColor(FONT_COLOR);
String text = (String)get(listField, index);
graphics.drawText(text, PAD, y + PAD, DrawStyle.LEFT);
graphics.setColor(oldColor);
}
public Object get(ListField listField, int index) {
return _rowData[index];
}
public int getPreferredWidth(ListField listField) {
return Display.getWidth();
}
public int indexOfList(ListField listField, String prefix, int start) {
return -1; // TODO?
}
}
}
You didn't specify how you wanted the list in the middle to work, so I just made some guesses. I also wasn't sure if the red border was something you wanted, or just something you used to describe your layout. Edit your question, or post a new question, if you have more requirements for the list.
Field Concepts
If you're coming from Android, and are unclear about the role of BlackBerry UI classes, like Fields and Managers, here's some resources:
another Stack Overflow answer I posted
BlackBerry Advanced UI Sample Code on Github
BlackBerry Layout Managers Tutorial
Results

To attach a ButtonField on every row of CustomListField in BlackBerry [duplicate]

i m writing one application in which i have created custom list field for displaying listview.
my CustomListField contains one image and text in a row. i m gettiing field change listener on click of listfield row but i want to put fieldchange listener on image too..
can anyone tell me how can i do that.
here is my code.
public class CustomListField extends ListField implements ListFieldCallback {
private Vector _listData;
private int _MAX_ROW_HEIGHT = 60;
public CustomListField(Vector data) {
_listData = data;
setSize(_listData.size());
setSearchable(true);
setCallback(this);
setRowHeight(_MAX_ROW_HEIGHT);
}
protected void drawFocus(Graphics graphics, boolean on) {
XYRect rect = new XYRect();
graphics.setGlobalAlpha(150);
graphics.setColor(Color.BLUE);
getFocusRect(rect);
drawHighlightRegion(graphics, HIGHLIGHT_FOCUS, true, rect.x, rect.y, rect.width, rect.height);
}
public int moveFocus(int amount, int status, int time) {
this.invalidate(this.getSelectedIndex());
return super.moveFocus(amount, status, time);
}
public void onFocus(int direction) {
super.onFocus(direction);
}
protected void onUnFocus() {
this.invalidate(this.getSelectedIndex());
}
public void refresh() {
this.getManager().invalidate();
}
public void drawListRow(ListField listField, Graphics graphics, int index, int y, int w) {
listField.setBackground(BackgroundFactory.createBitmapBackground(Bitmap.getBitmapResource("listing_bg.png")));
ListRander listRander = (ListRander) _listData.elementAt(index);
graphics.setGlobalAlpha(255);
graphics.setFont(Font.getDefault().getFontFamily().getFont(Font.PLAIN, 24));
final int margin = 5;
final Bitmap thumb = listRander.getListThumb();
final String listHeading = listRander.getListTitle();
final Bitmap nevBar = listRander.getNavBar();
// list border
graphics.setColor(Color.GRAY);
graphics.drawRect(0, y, w, _MAX_ROW_HEIGHT);
// thumbnail border & thumbnail image
graphics.setColor(Color.BLACK);
// graphics.drawRoundRect(margin-2, y+margin-2,thumb.getWidth()+2, thumb.getHeight()+2, 5, 5);
graphics.drawBitmap(margin, y + margin, thumb.getWidth(), thumb.getHeight(), thumb, 0, 0);
// drawing texts
// graphics.setFont(Font.BOLD);
graphics.drawText(listHeading, margin + thumb.getWidth(), y + margin);
graphics.setColor(Color.GRAY);
// graphics.setFont(Font.smallFont); // graphics.drawText(listDesc, 2*margin+thumb.getWidth(), y+ margin+20); // //
// graphics.drawText(listDesc2, 2*margin+thumb.getWidth(), y+ margin+32);
// draw navigation button
final int navBarPosY = y + (_MAX_ROW_HEIGHT / 2 - nevBar.getHeight() / 2);
final int navBarPosX = Graphics.getScreenWidth() - nevBar.getWidth() + margin;
graphics.drawBitmap(navBarPosX, navBarPosY, nevBar.getWidth(), nevBar.getHeight(), nevBar, 0, 0);
}
public Object get(ListField listField, int index) {
String rowString = (String) _listData.elementAt(index);
return rowString;
}
public int indexOfList(ListField listField, String prefix, int start) {
for (Enumeration e = _listData.elements(); e.hasMoreElements();) {
String rowString = (String) e.nextElement();
if (rowString.startsWith(prefix)) {
return _listData.indexOf(rowString);
}
}
return 0;
}
public int getPreferredWidth(ListField listField) {
return 3 * listField.getRowHeight();
}
/*
protected boolean trackwheelClick(int status, int time) {
invalidate(getSelectedIndex());
Dialog.alert(" U have selected :" + getSelectedIndex());
return super.trackwheelClick(status, time);
}
*/
}
i want to put click listner on star image of listfield row
and following is output of abbove code.
I did something very similar to this on a past project:
Background
As Arhimed said in his answer, and as you can read about on the BlackBerry forums here, you can't have full-fledged Field objects within the ListField. The content of ListField rows is just drawn directly in drawListRow() as text, and Bitmaps, etc. The contents aren't Field instances, and therefore, are not focusable.
So, what I did was to replace ListField with a subclass of Manager. Originally, I used a VerticalFieldManager, but I ran into problems with that. I've also been seeing a lot of issues on stack overflow, where people subclass VerticalFieldManager, customize just one small behaviour, and everything starts breaking. It seems to me that VerticalFieldManager works well if you accept its normal behaviour, and if you need something more, just extend Manager directly. Performing layout for vertically stacked rows is pretty easy.
I then made each row its own Manager, and implemented custom layout in sublayout() to place the row's Fields where I wanted them. I could then also make the row focusable, and then a bitmap/button on the row separately focusable (like your star). Clicking the row invokes one action, and clicking the star invokes another one.
I will note, however, that in my app, performance was not an issue, because I only had 10-20 rows. Also, I did have to modify my code to match your example, so consider this code only lightly tested. However, I did build it into an app, so it should perform fine as long as my assumptions, and your description were valid.
Implementation
First, it wasn't clear to me what your ListRander is (you didn't show that code). However, in my code, I need a data class to contain details about one row. It looked like that's how you used ListRander, so that's what I used:
public class ListRander {
private String _title;
private Bitmap _thumb;
public ListRander(String title, Bitmap thumb) {
_title = title;
_thumb = thumb;
}
public String getTitle() {
return _title;
}
public Bitmap getThumb() {
return _thumb;
}
}
Then, I replaced your CustomListField class with my own:
public class CustomListField extends Manager implements FocusChangeListener {
private int _MAX_ROW_HEIGHT = 60;
private boolean _searchable = false;
private Vector _listData;
private FieldChangeListener _fieldListener;
public CustomListField(Vector data) {
super(FOCUSABLE | VERTICAL_SCROLL | VERTICAL_SCROLLBAR);
setSearchable(true);
setEditable(false);
setListData(data);
}
public void setChangeListener(FieldChangeListener listener) {
// we need to save this listener, because we set it to listen to all new rows
_fieldListener = listener;
int numFields = getFieldCount();
for (int f = 0; f < numFields; f++) {
getField(f).setChangeListener(listener);
}
super.setChangeListener(listener);
}
public int getRowHeight() {
return _MAX_ROW_HEIGHT;
}
public void setSearchable(boolean searchable) {
_searchable = searchable;
}
public int getSelectedIndex() {
return getFieldWithFocusIndex(); // TODO??
}
public Object get(int index) {
return _listData.elementAt(index);
}
public int indexOfList(String prefix, int start) {
if (start >= _listData.size() || !_searchable) {
return -1;
} else {
int result = getSelectedIndex(); // the default result if we find no matches
for (Enumeration e = _listData.elements(); e.hasMoreElements(); ) {
String rowString = (String) e.nextElement();
if (rowString.startsWith(prefix)) {
return _listData.indexOf(rowString);
}
}
return result;
}
}
protected boolean navigationClick(int status, int time) {
CustomListRow focus = (CustomListRow) getFieldWithFocus();
if (focus != null) {
// see if the row wants to process this click
if (!focus.navigationClick(status, time)) {
// let our FieldChangeListener know that this row has been clicked
fieldChangeNotify(getFieldWithFocusIndex());
}
return true;
} else {
return false;
}
}
protected void sublayout(int width, int height) {
int w = Math.min(width, getPreferredWidth());
int h = Math.min(height, getPreferredHeight());
int rowHeight = getRowHeight();
int numRows = getFieldCount();
setExtent(w, h);
setVirtualExtent(w, rowHeight * numRows);
for (int i = 0; i < numRows; i++) {
Field f = getField(i);
setPositionChild(f, 0, rowHeight * i);
layoutChild(f, w, rowHeight);
}
}
public int getPreferredWidth() {
return Display.getWidth();
}
public int getPreferredHeight() {
return Display.getHeight();
}
public void setListData(Vector listData) {
_listData = listData;
if (listData != null) {
int listSize = listData.size();
int numRows = getFieldCount();
for (int s = 0; s < listSize; s++) {
if (s < numRows) {
// we can reuse existing CustomListRows
CustomListRow row = (CustomListRow) getField(s);
row.setData((ListRander) listData.elementAt(s));
} else {
CustomListRow row = new CustomListRow((ListRander) listData.elementAt(s));
row.setChangeListener(_fieldListener);
row.setFocusListener(this);
add(row);
}
}
if (listSize < numRows) {
// delete the excess rows
deleteRange(listSize, numRows - listSize);
}
} else {
deleteAll();
}
invalidate();
}
public void focusChanged(Field field, int eventType) {
// we handle scrolling here, when focus changes between rows
if (eventType == FOCUS_GAINED) {
if (field.getTop() < getVerticalScroll()) {
// field is off the top of the screen, so scroll up
setVerticalScroll(field.getTop());
} else if (field.getTop() >= getVerticalScroll() + getVisibleHeight()) {
// field is off the bottom of the screen, so scroll down
setVerticalScroll(field.getTop() - getVisibleHeight() + getRowHeight());
}
}
}
}
Finally, one row is represented by my CustomListRow class:
public class CustomListRow extends Manager implements FieldChangeListener {
private static final int _MAX_ROW_HEIGHT = 60;
private ListRander _data;
private BitmapField _thumb;
private LabelField _title;
private FocusableBitmapField _star;
private static final Bitmap _starImg = Bitmap.getBitmapResource("star.png");
private static final Bitmap _bgImg = Bitmap.getBitmapResource("listing_bg.png");
private SeparatorField _separator;
private int _fontColor = Color.BLACK;
private boolean _highlighted = false;
private int _width;
// subclass exists to expose focus methods (make public)
private class FocusableBitmapField extends BitmapField {
public FocusableBitmapField() {
super(_starImg, BitmapField.FOCUSABLE | BitmapField.EDITABLE);
}
public void onFocus(int direction) {
super.onFocus(direction);
}
public void onUnfocus() {
super.onUnfocus();
}
}
public CustomListRow(ListRander data) {
super(Field.FOCUSABLE | Manager.NO_VERTICAL_SCROLL | Manager.NO_VERTICAL_SCROLLBAR);
setBackground(BackgroundFactory.createBitmapBackground(_bgImg));
_width = Display.getWidth();
long labelStyle = (DrawStyle.LEFT | DrawStyle.TOP | DrawStyle.ELLIPSIS);
_title = new LabelField("", labelStyle) { // custom anonymous class to change font color
protected void paint(Graphics g) {
int c = g.getColor();
g.setColor(_fontColor);
super.paint(g);
g.setColor(c);
}
};
_title.setFont(Font.getDefault().getFontFamily().getFont(Font.PLAIN, 24));
_thumb = new BitmapField();
_star = new FocusableBitmapField();
_star.setChangeListener(this);
_separator = new SeparatorField() { // custom anonymous class to change separator color
protected void paint(Graphics g) {
int c = g.getColor();
g.setColor(Color.GRAY);
super.paint(g);
g.setColor(c);
}
};
setData(data);
add(_thumb);
add(_title);
add(_star);
add(_separator);
}
public ListRander getData() {
return _data;
}
public void setData(ListRander value) {
if (value != _data) {
_data = value;
_title.setText(value.getTitle());
_thumb.setBitmap(value.getThumb());
}
}
private void onStarClicked() {
Dialog.alert("Star has been clicked or tapped!");
}
private void onRowClicked() {
Dialog.alert("Row has been clicked or tapped!");
}
public void fieldChanged(Field field, int context) {
if (field == _star) {
onStarClicked();
}
}
public boolean navigationClick(int status, int time) {
if (_star.isFocus()) {
onStarClicked();
return true;
} /* else {
onRowClicked();
return true;
} */
return false; // we will not consume this event
}
protected void highlight(boolean onRow) {
_fontColor = onRow ? Color.WHITE : Color.BLACK; // change font color for contrast
_highlighted = onRow;
invalidate();
}
protected void onFocus(int direction) {
// called when focus first transfers to this row, from another Field
if (direction == 1) {
// coming from top to bottom, we highlight the row first, not the star
highlight(true);
} else if (direction == -1) {
// coming from bottom to top, we highlight the star button first, not the row
_star.onFocus(direction);
highlight(false);
}
}
protected void onUnfocus() {
// remove highlighting of the row, if any
highlight(false);
super.onUnfocus();
}
protected int moveFocus(int amount, int status, int time) {
// called when this row already has focus (either on row, or star button)
if (amount > 0) {
// moving top to bottom
if (!_star.isFocus()) {
// we were on the row, now move to the star button
_star.onFocus(1);
highlight(false);
amount--; // consume one unit of movement
}
} else {
// moving from bottom to top
if (_star.isFocus()) {
// we were on the star button, now move back over to the row
_star.onUnfocus();
highlight(true);
amount++; // consume one unit of movement
}
}
return amount;
}
protected boolean touchEvent(net.rim.device.api.ui.TouchEvent event) {
// We take action when the user completes a click (a.k.a. unclick)
int eventCode = event.getEvent();
if ((eventCode == TouchEvent.UNCLICK) || (eventCode == TouchEvent.DOWN)) {
// Get the touch location, within this Manager
int x = event.getX(1);
int y = event.getY(1);
if ((x >= 0) && (y >= 0) && (x < _width) && (y < _MAX_ROW_HEIGHT)) {
int field = getFieldAtLocation(x, y);
if ((field >= 0) && (getField(field) == _star)) {
// Let event propagate to (star) button field
return super.touchEvent(event);
} else {
if (eventCode == TouchEvent.UNCLICK) {
// A completed click anywhere else in this row should popup details for this selection
fieldChangeNotify(1);
onRowClicked();
} else {
// This is just a soft touch (TouchEvent.DOWN), without full click
setFocus();
}
// Consume the event
return true;
}
}
}
// Event wasn't for us, let superclass handle in default manner
return super.touchEvent(event);
}
protected void sublayout(int width, int height) {
height = Math.min(getPreferredHeight(), height);
setExtent(_width, height);
final int margin = 5;
int thumbWidth = _thumb.getPreferredWidth();
layoutChild(_thumb, thumbWidth, _thumb.getPreferredHeight());
setPositionChild(_thumb, margin, margin);
int starWidth = _star.getPreferredWidth();
int starHeight = _star.getPreferredHeight();
layoutChild(_star, starWidth, starHeight);
setPositionChild(_star, width - starWidth - margin, (height - starHeight) / 2);
// this assumes you want margin between all fields, and edges
layoutChild(_title, width - thumbWidth - starWidth - 4 * margin, _title.getPreferredHeight());
setPositionChild(_title, margin + thumbWidth /* + margin */, margin); // TODO?
}
protected void paintBackground(Graphics g) {
super.paintBackground(g);
if (_highlighted) {
// you can't override drawFocus() for a Manager, so we'll handle that here:
int oldColor = g.getColor();
int oldAlpha = g.getGlobalAlpha();
XYRect rect = new XYRect();
g.setGlobalAlpha(150);
g.setColor(Color.BLUE);
getFocusRect(rect);
drawHighlightRegion(g, HIGHLIGHT_FOCUS, true, rect.x, rect.y, rect.width, rect.height);
g.setGlobalAlpha(oldAlpha);
g.setColor(oldColor);
}
}
public int getPreferredWidth() {
return _width;
}
public int getPreferredHeight() {
return _MAX_ROW_HEIGHT;
}
}
Usage
This is how you might use the whole list field (maybe in a Screen class):
public class ListScreen extends MainScreen implements FieldChangeListener {
public ListScreen() {
try {
Vector data = new Vector();
Bitmap icon = Bitmap.getBitmapResource("list_icon.png");
for (int i = 0; i < 15; i++) {
ListRander lr = new ListRander("Product Name " + i, icon);
data.addElement(lr);
}
CustomListField list = new CustomListField(data);
add(list);
list.setChangeListener(this);
} catch (Exception e) {
e.printStackTrace();
}
}
public void fieldChanged(Field field, int context) {
if (field instanceof CustomListRow) {
CustomListRow row = (CustomListRow) field;
Dialog.alert(row.getData().getTitle() + " was selected!");
}
}
}
In my app, it made sense for the CustomListRow itself to handle the equivalent of your star click. However, for me, it did not make sense to have the row click handled that way. So, I let you set a FieldChangeListener on the CustomListField itself, which is called back when any row is selected. See the example above in my screen class. If you want to handle the row click inside the CustomListRow class, too, that's fine. I laid out a onRowClicked() method there. Search in the code for where that's commented out, and you can reactivate, an implement that method (onRowClicked()).
Issues
My app didn't require list searching. I laid out a sample implementation of that, like ListField has. But, I didn't test it. That's your job, if you need it. I just got you started with the CustomListField implementation (see indexOfList()).
I didn't see what your "nav bar" was for. A bar is usually a full-width item, like a status bar, or toolbar. I don't see anything like that in your screenshot. A nav item might be a little arrow at the right side of each row, to bring up details. But, I didn't see that in your screenshot either. So, I ignored that code. If you need a nav bar, you obviously know what it should be, and can add that to my code above.
I couldn't tell whether or not you just added the star as part of the row's background image, or if you had a separate image for that. I added a separate star.png to represent the star. I would assume that clicking the star fills it in, or highlights it, or something. But, you didn't describe that problem, so I assume you can handle that. If you need a custom field to represent the star, that can have selected and unselected images, just post that as a new question.
You had some code that appeared like it was trying to set the row width to 3x the row height, but that didn't match your screen shot. Most lists are full-screen width anyway. So, I remove that code. My CustomListRow class implements getPreferredWidth() and requests the full screen width. Change if you like.
Unlike Android's ListView the BB's ListField is not designed to have a focusable/clickable fields inside of list items. So any attempt to workaround this will have some negative side effects.
A relatively easy/quick workaround would be to switch to VerticalFieldManager (check this other stack overflow question). But if the list is too long (more than several hundreds, I believe) you risk to "eat" too much memory.
If the app is designed for touch screens only, then you can try to stay with ListField + do some manual tracking of touch event coordinates. So when you detect a list field click (in a way you would normally do it) you can check whether the touch coordinates correspond to the star image area (at least on the X axis). I am not going to invent/provide an implementation, but just giving an idea.

Custom BitmapField bug on unfocus and scroll (BlackBerry)

I have been having this annoying problem when trying to implement a picture gallery on BlackBerry 6.
Everything works, however when the focus changes from the top buttons to say the pictures further down the screen, the images seem to glitch and not paint themselves correctly. Please see the images below for an example:
(Focus is on the top of the screen(not shown))
(Focus is now on the bottom left image, note that the top image is now blank for an unknown reason)
And this happens no matter how many pictures I add to the tumbnail gallery.
Now here is my code, (a part of it concerning the drawing of the thumbnails)
public ProductImage(String productName){
super(VERTICAL_SCROLL|VERTICAL_SCROLLBAR);
currentProduct = productName;
createGUI();
}
public void createGUI(){
deleteAll();
try{
Storage.loadPicture();
}catch(NullPointerException e){
e.printStackTrace();
}
this.setTitle(new LabelField(_resources.getString(PRODUCT_IMAGE), Field.FIELD_HCENTER));
if(ToolbarManager.isToolbarSupported())
{
Toolbar tb = new Toolbar();
setToolbar(tb.createToolBar());
}
else{
Toolbar tb = new Toolbar();
add(tb.createNavBar());
}
picVector = Storage.getPicture(currentProduct);
EncodedImage enc = EncodedImage.getEncodedImageResource("camera.png");
EncodedImage sizeEnc = ImageResizer.sizeImage(enc, Display.getHeight(), Display.getHeight());
takenPicture = new BitmapField(enc.getBitmap());
vfMain = new VerticalFieldManager();
vfMain.add(logo);
vfMain.add(new SeparatorField());
add(vfMain);
prepareBmpFields();
}
private void prepareBmpFields() {
System.out.println("This is the vector size: " + picVector.getPicVector().size());
LayoutManager manager = new LayoutManager();
FieldChangeListener itemListener = new ButtonListener();
mBmpFields = new ImageButtonField[picVector.getPicVector().size()];
for (int i = 0; i < picVector.getPicVector().size(); i++) {
/*EncodedImage image = EncodedImage
.getEncodedImageResource((String)imageVector.elementAt(i));*/
byte[] data = getData((String)picVector.getPicVector().elementAt(i));
//Encode and Resize image
EncodedImage eImage = EncodedImage.createEncodedImage(data,0,data.length);
eImage = ImageResizer.resizeImage(eImage, mImgWidth, mImgHeight);
ImageButtonField currentImage = new ImageButtonField(eImage.getBitmap());
currentImage.setAssociatedPath((String)picVector.getPicVector().elementAt(i));
mBmpFields[i] = currentImage;
mBmpFields[i].setChangeListener(itemListener);
manager.add(mBmpFields[i]);
}
vfMain.add(manager);
}
private class LayoutManager extends VerticalFieldManager {
public LayoutManager() {
super(VERTICAL_SCROLL | VERTICAL_SCROLLBAR);
}
protected void sublayout(int width, int height) {
int columns = mScrWidth / (mImgWidth + 2 * mImgMargin);
int scrWidth = Display.getWidth();
int rows = mBmpFields.length / columns
+ (mBmpFields.length % columns > 0 ? 1 : 0);
int counter = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
int posX = j * (mImgWidth + 2 * mImgMargin) + mImgMargin;
int posY = i * (mImgHeight + 2 * mImgMargin) + mImgMargin;
if(mBmpFields.length > counter){
Field field = mBmpFields[counter];
layoutChild(field, mImgWidth, mImgHeight);
setPositionChild(field, posX, posY);
counter++;
};
}
}
if(Display.getWidth() < Display.getHeight()){
setExtent(mScrWidth, (int)(mScrHeight*1.25));
}
else{
setExtent(mScrWidth, (int)(mScrHeight*2));
}
}
public int getPreferredWidth() {
return mScrWidth;
}
public int getPreferredHeight() {
return mScrHeight;
}
}
}
I have removed many non relevant parts of the code, but the needed code is there.
Does anyone know what could be causing this problem? Thanks for your help!
Edit: as requested, here is my implementation of ImageButtonField class:
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Characters;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.BitmapField;
public class ImageButtonField extends BitmapField{
String associatedPath ="";
BitmapField image2;
public ImageButtonField(Bitmap image) {
super(image);
}
public void setAssociatedPath(String path){
associatedPath = path;
}
public String getAssociatedPath(){
return associatedPath;
}
public boolean isFocusable() {
return true;
}
protected void applyTheme(Graphics arg0, boolean arg1) {
}
protected void drawFocus(Graphics graphics, boolean on) {
}
protected void onFocus(int direction) {
// only change appearance if this button is enabled (aka editable)
if (isEditable()) {
invalidate(); // repaint
}
super.onFocus(direction);
}
public void onUnfocus() {
invalidate(); // repaint
super.onUnfocus();
}
protected boolean navigationClick(int status, int time) {
fieldChangeNotify(0);
return true;
}
protected boolean trackwheelClick(int status, int time) {
fieldChangeNotify(0);
return true;
}
protected void paint(Graphics graphics) {
super.paint(graphics);
if (isFocus()) {
graphics.setGlobalAlpha(128);
graphics.setColor(0x888888);
graphics.fillRect(0, 0, getWidth(), getHeight());
}else{
graphics.setGlobalAlpha(0);
graphics.setColor(0x000000);
graphics.fillRect(0, 0, getWidth(), getHeight());
//graphics.drawBitmap(0, 0, getWidth(), getHeight(), image2.getB, 0, 0);
}
}
protected boolean keyChar(char character, int status, int time) {
if(Characters.ENTER == character || Characters.SPACE == character) {
fieldChangeNotify(0);
return true;
}
return super.keyChar(character, status, time);
}
}
Ok, so you can disregard my first answer, but since I didn't have your ImageButtonField code at the time, I don't want to throw it out ... maybe someone else will find it useful.
In the end, I didn't need to make any changes to ImageButtonField, but I did change your LayoutManager class. The way I figured out that it was the problem was I just started replacing your custom UI classes with built-in ones. I replaced ImageButtonField with BitmapField. That didn't fix it. Then, I replaced LayoutManager with FlowFieldManager and that fixed it. So, I knew where the problem was.
My solution:
private class LayoutManager extends Manager {
public LayoutManager() {
super(VERTICAL_SCROLL | VERTICAL_SCROLLBAR);
}
protected void sublayout(int width, int height) {
setExtent(width, height);
// TODO: maybe always set the same virtual extent?
if (Display.getWidth() < Display.getHeight()) {
setVirtualExtent(mScrWidth, (int) (mScrHeight * 1.25));
} else {
setVirtualExtent(mScrWidth, (int) (mScrHeight * 2));
}
int columns = mScrWidth / (mImgWidth + 2 * mImgMargin);
// int scrWidth = Display.getWidth();
int rows = mBmpFields.length / columns + (mBmpFields.length % columns > 0 ? 1 : 0);
int counter = 0;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
int posX = j * (mImgWidth + 2 * mImgMargin) + mImgMargin;
int posY = i * (mImgHeight + 2 * mImgMargin) + mImgMargin;
if (mBmpFields.length > counter) {
Field field = mBmpFields[counter];
layoutChild(field, mImgWidth, mImgHeight);
setPositionChild(field, posX, posY);
counter++;
}
}
}
}
public int getPreferredWidth() {
return mScrWidth;
}
public int getPreferredHeight() {
return mScrHeight;
}
}
I can't say for sure that I understand why your original code wasn't working, but I can say that I wouldn't have done a few of the things in the original code:
The original code was extending VerticalFieldManager but was doing all the work itself, in sublayout(). So, I don't think there was any point extending VerticalFieldManager. I changed it to just extend Manager.
The original code was calling setExtent() with different sizes. I don't think that's what you wanted. Extent is the actual size of the Field. Virtual extent is the virtual size, which is what you want to set larger than the actual extent, in order to enable scrolling. You don't need to dynamically calculate different extents for portrait vs. landscape because the width and height parameters passed to sublayout() will already reflect that. I'm not sure you really even need to be setting different virtual extents either. I think you should probably always set the virtual extent height to the number of rows times picture height, accounting for margins.
You had an unused variable scrWidth in your original code. I commented it out above.
You also posted this question recently, right? Am I correct in assuming that the ImageButtonField you refer to here is the same one you were working on in the other question?
I can't see your full implementation of ImageButtonField, which you should probably post here, too. However, looking at the answers to your other question, I have a feeling that you're doing some custom focus handling in ImageButtonField, and maybe it's not being done quite right. In any case, that class may be where the problem is.
I have a similar Field subclass of my own, and here are the focus handling methods I define:
public class CustomButtonField extends Field {
private Bitmap _button; // the currently displayed button image
private Bitmap _on; // image for 'on' state (aka in-focus)
private Bitmap _off; // image for 'off' state (aka out-of-focus)
protected void onFocus(int direction) {
// only change appearance if this button is enabled (aka editable)
if (isEditable()) {
_button = _on;
invalidate(); // repaint
}
super.onFocus(direction);
}
protected void onUnfocus() {
_button = _off;
invalidate(); // repaint
super.onUnfocus();
}
protected void drawFocus(Graphics graphics, boolean on) {
// override superclass implementation and do nothing
}
public boolean isFocusable() {
return true;
}
I also have a custom implementation of paint(). I won't show it all here, because a lot of the code probably has nothing to do with your problem, but my paint() does include this call:
graphics.drawBitmap(_padding, _padding, _fieldWidth, _fieldHeight, _button, 0, 0);
You might not care about the fact that I have separate images for focused, and unfocused states ... maybe you show the same image at all times.
But, probably the thing to check is your onFocus() and onUnfocus() methods. You may need to add a call to invalidate() as I have.
Looking at Rupak's answer to your other question, it would also be good to check your ImageButtonField.paint() method, and make sure you aren't neglecting to do important drawing steps if the field is not in focus.

Custom editfield not displaying all typed text

Below class is a textbox field. Can this be modified so that when the textbox is filled with text and user keeps type the text then scrolls ? Whats happening now is that once the textbox is filled with text any subsequent text that is typed is not being displayed.
Thanks
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.EditField;
public class CustomEditField extends EditField {
// private members of the CustomEditField class
private Font defaultFont;
// used to get the default font
private String text;
// used to specify the default width of the table cells
// constructor calls the super class constructor
public CustomEditField(String label, String initialValue, int maxNumChars,
long style) {
super(label, initialValue, maxNumChars, style);
}
// overrides the default getPreferredWidth functionality to return a fixed
// width
public int getPreferredWidth() {
defaultFont = Font.getDefault();
text = "0000000000";
return defaultFont.getAdvance(text);
}
// overrides the default layout functionality to set the width of the table
// cell
protected void layout(int width, int height) {
width = getPreferredWidth();
height = super.getPreferredHeight();
super.layout(width, height);
// uses the super class' layout functionality
// after the width and the height are set
super.setExtent(width, height);
// uses the super class' setExtent functionality
// after the width and the height are set
}
public void paint(Graphics graphics){
graphics.setBackgroundColor(Color.LIGHTBLUE);
super.paint(graphics);
}
}
This will help you to get started. It is a simplified version of the ScrollableEditField that I am using. I coded it before touch BlackBerry devices became available, therefore some additional work is required here to support TouchEvents.
class ScrollableEditField extends Manager {
private final static int DEFAULT_TOP_PADDING = 1;
private final static int DEFAULT_BOTTOM_PADDING = 1;
private final static int DEFAULT_LEFT_PADDING = 1;
private final static int DEFAULT_RIGHT_PADDING = 1;
private int TOTAL_VERTICAL_PADDING = DEFAULT_TOP_PADDING + DEFAULT_BOTTOM_PADDING;
private int TOTAL_HORIZONTAL_PADDDING = DEFAULT_LEFT_PADDING + DEFAULT_RIGHT_PADDING;
private int width = -1;
private int height = -1;
private HorizontalFieldManager hfm = new HorizontalFieldManager(HORIZONTAL_SCROLL);
private EditField ef;
public ScrollableEditField(String label, String initialValue, int maxNumChars, long innerEditFieldStyle) {
super(NO_HORIZONTAL_SCROLL);
ef = new EditField(label, initialValue, maxNumChars, innerEditFieldStyle);
hfm.add(ef);
add(hfm);
}
protected void sublayout(int width, int height) {
if (this.width != -1) {
width = this.width;
}
if (this.height != -1) {
height = this.height;
} else {
height = ef.getFont().getHeight();
}
layoutChild(hfm, width-TOTAL_HORIZONTAL_PADDDING, height-TOTAL_VERTICAL_PADDING);
setPositionChild(hfm, DEFAULT_LEFT_PADDING, DEFAULT_TOP_PADDING);
setExtent(width, height);
}
public EditField getEditField() {
return ef;
}
public void setWidth(int width) {
this.width = width;
}
protected void onFocus(int direction) {
super.onFocus(direction);
ef.setCursorPosition(0);
}
protected void onUnfocus() {
hfm.setHorizontalScroll(0);
super.onUnfocus();
}
};
public class ScrollableEditFieldScreen extends MainScreen {
public ScrollableEditFieldScreen() {
super(NO_VERTICAL_SCROLL);
setTitle("ScrollableEditField");
// hfm1 and hfm2 are here just to position the ScrollableEditField in the center of the screen
HorizontalFieldManager hfm1 = new HorizontalFieldManager(USE_ALL_HEIGHT | FIELD_HCENTER);
HorizontalFieldManager hfm2 = new HorizontalFieldManager(FIELD_VCENTER);
// instantiating the scrollable edit field and adding border
ScrollableEditField sef = new ScrollableEditField("", "", 50, 0);
sef.setBorder(BorderFactory.createRoundedBorder(new XYEdges(5,5,5,5)));
sef.setWidth(sef.getFont().getAdvance('0')*10);
hfm2.add(sef);
hfm1.add(hfm2);
add(hfm1);
}
}

Resources