I am trying to type in characters to fill an editfield, if the text is still on the first line I have got no problem but when the first line is full then it goes to the next line and I get the following error:
0:01:56.609: Uncaught: StackOverflowError
Here is my custom_editfield:
public class Custom_EditField extends EditField {
int width, row;
Custom_EditField(long style, int width, int row) {
super(style);
this.width = width;
this.row = row;
}
public int getPreferredHeight() {
return Font.getDefault().getHeight() * row;
}
public int getPreferredWidth() {
return width;
}
protected void layout(int maxWidth, int maxHeight) {
super.layout(maxWidth,
Math.min(maxHeight, Font.getDefault().getHeight() * row));
super.setExtent(maxWidth,
Math.min(maxHeight, Font.getDefault().getHeight() * row));
}
/*public int drawText(Graphics graphics, int offset, int length, int x,
int y, DrawTextParam drawTextParam) {
graphics.setBackgroundColor(Color.GRAY);
graphics.clear();
graphics.setColor(Color.BLACK);
int labelWidth = getFont().getAdvance(getLabel());
graphics.drawRect(labelWidth, 0, getWidth() - labelWidth, getHeight());
return graphics.drawText(
this.getText().substring(offset, offset + length), x, y);
}*/
protected void paint(Graphics graphics) {
int rectHeight = getPreferredHeight();
int rectWidth = getPreferredWidth();
graphics.setBackgroundColor(Color.GRAY);
graphics.clear();
graphics.setColor(Color.BLACK);
graphics.drawRect(0, 0, rectWidth, rectHeight);
super.paint(graphics);
}
}
I also noticed that the cursor is transparent. Do you think that the cursor could cause this problem?
Here is I call the editfield
extends VerticalFIeldManager
protected void sublayout(int width, int height) {
comments = new Custom_EditField(Field.FIELD_HCENTER
| Field.FIELD_VCENTER | Field.FOCUSABLE,
getPreferredWidth() - 10, 3);
add(comments);
namelabel = new Custom_LabelField("姓名:", DrawStyle.ELLIPSIS
| LabelField.USE_ALL_WIDTH | DrawStyle.LEFT | Field.FIELD_LEFT);
namelabel.setFont(Font.getDefault().derive(Font.BOLD, 20));
namelabel.setFontColor(Color.BLACK);
add(namelabel);
postbtn = new ButtonField("留言", DrawStyle.HCENTER | Field.FIELD_RIGHT);
postbtn.setPadding(0, 20, 0, 20);
postbtn.setChangeListener(this);
add(postbtn);
name = new Custom_EditField(Field.FIELD_HCENTER | Field.FIELD_VCENTER
| Field.FOCUSABLE, getPreferredWidth()
- namelabel.getPreferredWidth() - postbtn.getContentWidth() - 5
* 4, 1);
add(name);
Field field = getField(0);
layoutChild(field, getPreferredWidth() - 10,
comments.getPreferredHeight());
setPositionChild(field, 5, 5);
field = getField(1);
layoutChild(field, Font.getDefault().getAdvance(namelabel.getText()),
namelabel.getContentHeight());
setPositionChild(field, 5, comments.getPreferredHeight() + 5 * 2);
field = getField(2);
layoutChild(field, postbtn.getPreferredWidth() + postbtn.getWidth(),
name.getPreferredHeight());
setPositionChild(field, getPreferredWidth() - (postbtn.getWidth() + 5),
comments.getPreferredHeight() + 5 * 2);
field = getField(3);
layoutChild(field, getPreferredWidth() * 2 / 3,
name.getPreferredHeight());
setPositionChild(field, namelabel.getWidth(),
comments.getPreferredHeight() + 5 * 2);
width = Math.min(width, getPreferredWidth());
height = Math.min(height, getPreferredHeight());
setExtent(width, height);
}
The Solution
I still can't build your code, because the Manager code posted uses the class Custom_LabelField, which you haven't shown. However, I would assume that Custom_LabelField is somewhat like a LabelField. If I assign name to be a LabelField, then I see your StackOverflowError.
Just as #EugenMartynov said, you are setting the text of a label field inside your implementation of sublayout(). This actually causes sublayout() to be called again, from within itself. This causes namelabel to be created again, and the process repeats infinitely until the stack is exhausted.
Really, the sublayout() method should only be used for layout operations: positioning and sizing. You should normally create your Field objects before that. Normally, that happens in the constructor. If you move the first half of your sublayout method to the constructor, you'll fix this problem:
public class MyManager extends VerticalFieldManager {
public MyManager() {
super(Manager.VERTICAL_SCROLL | Manager.VERTICAL_SCROLLBAR);
comments = new Custom_EditField(Field.FIELD_HCENTER
| Field.FIELD_VCENTER | Field.FOCUSABLE,
getPreferredWidth() - 10, 3);
add(comments);
namelabel = new Custom_LabelField("姓名:", DrawStyle.ELLIPSIS
| LabelField.USE_ALL_WIDTH | DrawStyle.LEFT | Field.FIELD_LEFT);
namelabel.setFont(Font.getDefault().derive(Font.BOLD, 20));
namelabel.setFontColor(Color.BLACK);
add(namelabel);
postbtn = new ButtonField("留言", DrawStyle.HCENTER | Field.FIELD_RIGHT);
postbtn.setPadding(0, 20, 0, 20);
postbtn.setChangeListener(this);
add(postbtn);
name = new Custom_EditField(Field.FIELD_HCENTER | Field.FIELD_VCENTER
| Field.FOCUSABLE, getPreferredWidth()
- namelabel.getPreferredWidth() - postbtn.getContentWidth() - 5
* 4, 1);
add(name);
}
}
Then sublayout() becomes simpler:
protected void sublayout(int height, int width) {
Field field = getField(0);
layoutChild(field, getPreferredWidth() - 10,
comments.getPreferredHeight());
setPositionChild(field, 5, 5);
field = getField(1);
layoutChild(field, Font.getDefault().getAdvance(namelabel.getText()),
namelabel.getContentHeight());
setPositionChild(field, 5, comments.getPreferredHeight() + 5 * 2);
field = getField(2);
layoutChild(field, postbtn.getPreferredWidth() + postbtn.getWidth(),
name.getPreferredHeight());
setPositionChild(field, getPreferredWidth() - (postbtn.getWidth() + 5),
comments.getPreferredHeight() + 5 * 2);
field = getField(3);
layoutChild(field, getPreferredWidth() * 2 / 3,
name.getPreferredHeight());
setPositionChild(field, namelabel.getWidth(),
comments.getPreferredHeight() + 5 * 2);
width = Math.min(width, getPreferredWidth());
height = Math.min(height, getPreferredHeight());
setExtent(width, height);
}
General Information
If you want to know how to catch a StackOverflowError, put this code in your top level UiApplication subclass (just for debugging ... remove it before releasing your app):
try {
MyApp theApp = new MyApp();
theApp.enterEventDispatcher();
} catch (Throwable e) {
e.printStackTrace();
}
After it hits the line e.printStackTrace(), your Eclipse Console window will show something like this:
[375.664] 0x16
[375.664] HelloBlackBerry(4FF4123E)
[375.664] MyManager
[375.664] sublayout
[375.664] 0x16
[375.664] HelloBlackBerry(4FF4123E)
[375.664] MyManager
[375.664] sublayout
[375.664] 0x16
[375.664] HelloBlackBerry(4FF4123E)
[375.664] MyManager
[375.664] sublayout
[375.664] 0x16
[375.664] HelloBlackBerry(4FF4123E)
[375.664] MyManager
[375.664] sublayout
[375.664] 0x16
[375.664] HelloBlackBerry(4FF4123E)
You can see, over and over, with almost the exact same timestamp (375.664), the sublayout method in the MyManager class is being called. When you see that, you know you need to look at that method, because it's calling itself.
Related
I have written the following code here the background image is displaying but the image did not cover the full background
private Bitmap background;
int mWidth = Display.getWidth();
int mHeight = Display.getHeight();
public MyScreen()
{
// Set the displayed title of the screen
//backgroundBitmap = Bitmap.getBitmapResource("slidimage.png");
final Bitmap background = Bitmap.getBitmapResource("slidimage.png");
HorizontalFieldManager vfm = new HorizontalFieldManager(USE_ALL_HEIGHT | USE_ALL_WIDTH) {
public void paint(Graphics g) {
g.drawBitmap(0, 0,mWidth, mHeight, background, 0, 0);
super.paint(g);
}
};
add(vfm);
public static Bitmap resizeBitmap(Bitmap image, int width, int height)
{
int rgb[] = new int[image.getWidth()*image.getHeight()];
image.getARGB(rgb, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight());
int rgb2[] = rescaleArray(rgb, image.getWidth(), image.getHeight(), width, height);
Bitmap temp2 = new Bitmap(width, height);
temp2.setARGB(rgb2, 0, width, 0, 0, width, height);
return temp2;
}
You can use the above method to resize the image
just pass the image to be resized and its width and height .
and the function will return the resized image .
where rescale Array is the below method
private static int[] rescaleArray(int[] ini, int x, int y, int x2, int y2)
{
int out[] = new int[x2*y2];
for (int yy = 0; yy < y2; yy++)
{
int dy = yy * y / y2;
for (int xx = 0; xx < x2; xx++)
{
int dx = xx * x / x2;
out[(x2 * yy) + xx] = ini[(x * dy) + dx];
}
}
return out;
}
I had an custom editfield
public class Custom_EditField extends EditField {
int width, row;
Custom_EditField(long style, int width, int row) {
super(style);
this.width = width;
this.row = row;
}
protected void layout(int width, int height) {
width = this.width;
height = this.row;
super.layout(width, Font.getDefault().getHeight() * row);
super.setExtent(width, Font.getDefault().getHeight() * row);
}
public int getPreferredHeight() {
return Font.getDefault().getHeight() * row;
}
public int getPreferredWidth() {
return width;
}
public void paint(Graphics graphics) {
super.paint(graphics);
graphics.setBackgroundColor(Color.GRAY);
graphics.clear();
graphics.setColor(Color.BLACK);
int labelWidth = getFont().getAdvance(getLabel());
graphics.drawRect(labelWidth, 0, getWidth() - labelWidth, getHeight());
graphics.drawText(this.getText(), 0, 0);
}
}
When I type a full line of word in the editfield, it will cause and error. It seem like cannot auto go to next line.
The arguments to the layout method in BlackBerry UI are maximums, and your custom code makes no attempt to honor those maximums when setting the field extent. This will cause problems with your layout. Also, the paint() method is not the best place to alter drawing for text fields, because it doesn't understand text wrapping. If you want to alter how the text is drawn, but after the wrapping has been performed, you want to override drawText instead.
This is approximately what you want, but you will need to do some more tweaking to make it work the way you expect:
protected void layout(int maxWidth, int maxHeight) {
super.layout(maxWidth, Math.min(maxHeight, Font.getDefault().getHeight() * row));
super.setExtent(maxWidth, Math.min(maxHeight, Font.getDefault().getHeight() * row));
}
public int drawText(Graphics graphics,
int offset,
int length,
int x,
int y,
DrawTextParam drawTextParam) {
graphics.setBackgroundColor(Color.GRAY);
graphics.clear();
graphics.setColor(Color.BLACK);
int labelWidth = getFont().getAdvance(getLabel());
graphics.drawRect(labelWidth, 0, getWidth() - labelWidth, getHeight());
graphics.drawText(this.getText().substring(offset, offset + length), x, y);
}
This is my custom layout which was same as android linear layout
public class Custom_TopField extends VerticalFieldManager {
private static final int FIELD_HEIGHT = 70;
private String _text;
Custom_TopField(int color, String text) {
super(Manager.NO_VERTICAL_SCROLL);
_text = text;
Background background = BackgroundFactory.createSolidBackground(color);
setBackground(background);
}
protected void sublayout(int width, int height) {
width = Math.min(width, getPreferredWidth());
height = Math.min(height, getPreferredHeight());
setExtent(width, height);
}
public int getPreferredHeight() {
return FIELD_HEIGHT;
}
public int getPreferredWidth() {
return Display.getWidth();
}
public void paint(Graphics graphics) {
int rectHeight = getPreferredHeight();
int rectWidth = getPreferredWidth();
Font font = Font.getDefault().derive(Font.BOLD, 65);
graphics.drawRect(0, 0, rectWidth, rectHeight);
graphics.drawText(_text, rectWidth / 2, 10);
graphics.setFont(font);
graphics.setColor(Color.WHITE);
super.paint(graphics);
}
}
Output = background red and font = black
What I want is background red, font white, font size 40.
I also want to know how to create widget programmatically?
To set the font to white and the size to 40 change the paint as follows:
public void paint(Graphics graphics) {
int rectHeight = getPreferredHeight();
int rectWidth = getPreferredWidth();
Font font = Font.getDefault().derive(Font.BOLD, 40);
graphics.setColor(Color.WHITE);
graphics.setFont(font);
graphics.drawRect(0, 0, rectWidth, rectHeight);
graphics.drawText(_text, rectWidth / 2, 10);
super.paint(graphics);
}
I want to add a bar at the bottom of the screen which has images and a string ,i wanted to have the spacing equally like
img1 string img2|img3 ,this is how the bottom bar should look like,below code is not wroking properly i am gettign the alignment and the last iamge is getting disappeared.
HorizontalFieldManager horizontalFieldManager = new HorizontalFieldManager(
FIELD_BOTTOM) {
public void paint(Graphics graphics) {
graphics.setBackgroundColor(0x316AC5);
graphics.clear();
super.paint(graphics);
}
};
Bitmap fadeBitmap = Bitmap
.getBitmapResource("GE_TimeZone_Fade_blue.PNG");
Bitmap clockBitmap = Bitmap.getBitmapResource("GE_Cal_icon_blue.PNG");
Bitmap tzBitmap = Bitmap
.getBitmapResource("GE_TimeZone_Button_blue.PNG");
final ImageButtonField unfocus = new ImageButtonField("",
Field.FOCUSABLE | FIELD_LEFT, "GE_TimeZone_Fade_blue.PNG",
"GE_TimeZone_Fade_blue.PNG", 0xFFFFFF);
LabelField test = new LabelField("hello");
final ImageButtonField bitmapField = new ImageButtonField("",
Field.FOCUSABLE | FIELD_HCENTER, "GE_Cal_icon_blue.PNG",
"GE_Cal_icon_onSelect.PNG", 0xFFFFFF);
final ImageButtonField bitmapField1 = new ImageButtonField("",
Field.FOCUSABLE | FIELD_RIGHT, "GE_TimeZone_Button_blue.PNG",
"GE_TimeZone_Btn_OnSelect.PNG", 0xFFFFFF);
int margin = ((Display.getWidth() - (fadeBitmap.getWidth()
+ clockBitmap.getWidth() + tzBitmap.getWidth() + test
.getWidth())) / 4);
unfocus.setMargin(0, margin, 0, 0);
test.setMargin(0, margin, 0, 0);
bitmapField.setMargin(0, margin, 0, 0);
bitmapField1.setMargin(0, margin, 0, 0);
horizontalFieldManager.add(unfocus);
horizontalFieldManager.add(test);
horizontalFieldManager.add(bitmapField);
horizontalFieldManager.add(bitmapField1);
this.setStatus(horizontalFieldManager);
There is a problem on the code you are using. Check following line.
int margin = ((Display.getWidth() - (fadeBitmap.getWidth()
+ clockBitmap.getWidth() + tzBitmap.getWidth() + test
.getWidth())) / 4);
The getWidth() and getHeight() of any Field will return valid values if the layout method of it's parent manager gets called.
So, adjusting the margin using getWidth(), getHeight() is not safe.
But it is possible to control the alignment and position of the Fields via extending HorizontalFieldManager. Check the following codes and output to get an idea about how it can be done.
Output
Using the StatusFieldManager:
StatusFieldManager statusFieldManager = new StatusFieldManager();
statusFieldManager.setBackground(BackgroundFactory.createSolidBackground(0x316AC5));
final Bitmap bmTest = Bitmap.getBitmapResource("bitmap.png");
BitmapField bmOne = new BitmapField(bmTest, Field.FOCUSABLE | FIELD_LEFT);
BitmapField bmTwo = new BitmapField(bmTest, Field.FOCUSABLE | FIELD_LEFT);
BitmapField bmThree = new BitmapField(bmTest, Field.FOCUSABLE | FIELD_LEFT);
LabelField lblTest = new LabelField("Test");
statusFieldManager.add(bmOne);
statusFieldManager.add(lblTest);
statusFieldManager.add(bmTwo);
statusFieldManager.add(bmThree);
setStatus(statusFieldManager);
Implementation of StatusFieldManager
class StatusFieldManager extends HorizontalFieldManager {
protected void sublayout(int width, int height) {
int numField = getFieldCount();
Field f;
int nHeight = 0, maxFieldWidth = width / 4;
if (numField == 4) {
f = getField(0);
layoutChild(f, maxFieldWidth, height);
nHeight = Math.max(nHeight, f.getHeight());
f = getField(1);
layoutChild(f, maxFieldWidth, height);
nHeight = Math.max(nHeight, f.getHeight());
f = getField(2);
layoutChild(f, maxFieldWidth, height);
nHeight = Math.max(nHeight, f.getHeight());
f = getField(3);
layoutChild(f, maxFieldWidth, height);
nHeight = Math.max(nHeight, f.getHeight());
// set position of the child fields
int x = 0, y = 0;
int requiredFieldWidth = 0;
for (int i=0;i<numField;i++) {
requiredFieldWidth += getField(i).getWidth();
}
int spaceBetweenFields = (width - requiredFieldWidth) / (numField - 1);
for (int i=0;i<numField;i++) {
setPositionChild(getField(i), x, (nHeight - getField(i).getHeight()) / 2);
x += getField(i).getWidth() + spaceBetweenFields;
}
setExtent(width, nHeight);
} else {
setExtent(0, 0);
}
}
}
try this -
unfocus.setMargin(0, margin, 0, 0);
test.setMargin(0, 10, 0, 0);
bitmapField.setMargin(0, 10, 0, 0);
bitmapField1.setMargin(0, 10, 0, 0);
I am developing an application where I should use nested horizontalmanagers. I am taking inner and outer HFMs. The fields of innerHFM overlap on the outerHFM when I scroll the fields. How can I use setExtent method for innerHFM. My innerHFM contains fields like 1 2 3 4 5 and my outerHFM contains next and previous buttons. Here is the code I implemented
outerHFM = new HorizontalFieldManager() {
protected void sublayout(int maxWidth, int maxHeight) {
layoutChild(next, maxWidth, maxHeight);
setPositionChild(next, 300, 5);
layoutChild(innerHfm, 200, maxHeight);
setPositionChild(innerHfm, 10, 5);
layoutChild(previous, maxWidth, maxHeight);
setPositionChild(previous, 44, 5);
setExtent(maxWidth, 40);
}
};
innerHfm = new HorizontalFieldManager(Manager.HORIZONTAL_SCROLL|Manager.USE_ALL_WIDTH) {
protected void sublayout(int maxWidth, int maxHeight) {
int space = 0;
int x = 90;
for (int i = 0; i < cardsSize; i++) {
layoutChild(numbtn[i], 210, maxHeight);
setPositionChild(numbtn[i], x + space+offset, 0);
space = space + 50;
}
setExtent(240, 40);
}
};
Hi this sizing works for all my field managers.
int managerWidth;
int managerHeight;
public int getPreferredWidth() {
return managerWidth;
}
public int getPreferredHeight() {
return managerHeight;
}
public void sublayout(int w, int h) {
super.sublayout(managerWidth, managerHeight);
setExtent(managerWidth, managerHeight);
}
maybe that manualy positionig might be problem, you can use AbsoluteFieldManager instead...