How to display text in multi-line using customized label field in Blackberry?
When I use following code, I can display the label with desired font size, however the problem is when the extent is limited in width the text gets cut off and not displayed entirely , also rest of the label part is not displayed on next line.
Any Help here is appreciated.
Following is my code for customized label field.
public class GrayBgLabelField extends LabelField {
private int width = Display.getWidth();
private int height = 40;
private String label;
private Font font;
public GrayBgLabelField(){
super();
}
public GrayBgLabelField(String label, int fieldWidth){
super(label, 0 );
this.label = label;
width = fieldWidth;
}
public GrayBgLabelField(String label, int fieldWidth , long style){
super( label, style );
this.label = label;
width = fieldWidth;
}
public GrayBgLabelField(String label, int fieldWidth , int fieldHeight){
this(label,fieldWidth);
this.label = label;
height = fieldHeight;
}
public GrayBgLabelField(String label, int fieldWidth , int fieldHeight, long style){
super( label, style );
this.label = label;
width = fieldWidth;
height = fieldHeight;
}
protected void layout( int maxWidth, int maxHeight)
{
super.layout( width, height);
setExtent( width, height);
}
protected void paint(Graphics g) {
if(font !=null){
g.setFont(font);
}
if (label.length() != 0) {
g.drawText(label, width/30, height/4);
}
g.setColor(Color.BLACK);
}
public void setFont(int f){
font = this.getFont().derive(f);
}
public void setFont(Font font){
this.font = font;
}
protected void paintBackground(Graphics g) {
int oldColor = g.getColor();
try {
g.setColor(0xF5F6F8); // Gray-DDDDDD color code.
g.fillRect(0, 0, getWidth(), getHeight());
} finally {
g.setColor(oldColor);
}
}
}
Override methods which control width and height of your custom field.
Here is the tutorial: "How to create a custom field"
And when you change your label field text, invalidate it via invalidate() method, to redraw field contents on the screen.
Related
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
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?
In my app I need a scrollable field with non-editable text with custom size. I'm trying to do this like below:
final int sx2 = Display.getWidth()-Display.getWidth()*2/51-kButtonWidgh;
final int sy2 = Display.getHeight()*7/12;
VerticalFieldManager vfm3 = new VerticalFieldManager()
{
public void sublayout( int maxWidth, int maxHeight )
{
super.sublayout(sx2, sy2);
}
};
text = new TextField((Field.FOCUSABLE & Field.READONLY & Field.STATUS_MOVE_FOCUS_HORIZONTALLY)){
public void layout( int maxWidth, int maxHeight ) {
super.layout(sx2, sy2); //my custom frame
}
};
vfm3.add(text);
vfm2.add(vfm3);
But it editable, and not scrollable. Text prints from beginning field and ends far away from it's frame. there is cursor, which goes out of field frame, and there is no scrolling. How should I do this?
try this:
EditField _text = new EditField(Field.HORIZONTAL_SCROLL|Field.VERTICAL_SCROLL);
_text.setEditable(false);
When the user hovers over editfield below the touch screen keyboard does not display. What is displayed is a white area that is same size as keyboard. This is an issue on BlackBerry Torch. I would expect the touch screen keyboard to appear correctly using below code ?
BasicEditField nameField =
new BasicEditField(
" "+Local.getInfo8()+ " : ", "", 100, BasicEditField.FILTER_DEFAULT)
{
private int iRectX = getFont().getAdvance(getLabel());
private int iRectWidth = backgroundButtonBitmap.getWidth() - iRectX - 4;
public int getPreferredHeight() {
return backgroundButtonBitmap.getHeight() / 2;
}
public void layout(int width, int height) {
//setExtent(width, getPreferredHeight());
super.layout(width, getPreferredHeight());
}
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.setBackgroundColor(Color.WHITE);
//g.drawRect(iRectX, 0, iRectWidth, 20);
super.paint(g);
}
};
On the display screen, the method sublayout was being overriden -
protected void sublayout( int maxWidth, int maxHeight ) {
super.sublayout( maxWidth, maxHeight );
setExtent(maxWidth,Constants.BACKGROUND_IMAGE.getHeight());
}
The line - setExtent(maxWidth,Constants.BACKGROUND_IMAGE.getHeight()); is causing the issue.
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);
}
}