Blackberry RichTextField preferred height during layout - blackberry

This is using the Backberry JDK (5.0 if needed).
I have a custom Manager that contains a RichTextField. I want the height of the field to vary by the amount of text in the RichTextField.
The sublayout code looks like this (rtf is a RichTextField object):
protected void sublayout(int width, int height) {
int h = rtf.getPreferredHeight();
setExtent(Display.getWidth(), h);
layoutChild(rtf, Display.getWidth(), h);
setPositionChild(rtf, 0, 0);
setExtent(Display.getWidth(), h);
}
The call to rtf.getPreferredHeight always returns the same value, no matter how much text (and therefore how many lines on the screen).
Any clues on how to get the height of a RichTextField when the content and width are known?

Of course, as soon as I posted it I figured out the answer. Query the control after calling layoutChild.
This fixed it:
int h = rtf.getPreferredHeight();
layoutChild(rtf, Display.getWidth(), h);
h = rtf.getHeight();
setPositionChild(rtf, 0, 0);
setExtent(Display.getWidth(), h);
I would have deleted the question but maybe this will help someone else.

RichTextField deviceId = new RichTextField() {
protected void setExtent(int width, int height) {
super.setExtent(Display.getWidth() - 30, 25);
}
};
This solved my problem for setting height and width for RichTextField when you don't want to write separate class for it.

Related

Drawing Radial Gradients in Blackberry?

How do I draw a radial gradient button in BlackBerry? I found "Drawing Radial Gradients" on the BlackBerry support forums. All I am able to implement on my own is a linear gradient.
This is a little tricky. Drawing linear gradients on field backgrounds is easy. Drawing radial gradients on field backgrounds is harder. Doing it on a button is harder still.
First of all, the example you link to does indeed look really bad. The biggest problem with that code is that it uses Graphics.drawArc() to construct the gradient out of concentric circles (lines). This is not at all smooth.
The biggest improvement you need to make over that is to use Graphics.fillArc() instead, which will look much smoother (although there may be a performance impact to this ...).
Your question didn't say anything about how you wanted the button to look when focused, or whether the corners needed to be rounded. That's where some of the difficulty comes in.
If you just extend the RIM ButtonField class, you'll probably have trouble with the default drawing for focus, and edge effects. It's probably necessary to directly extend the base Field class in a new, written-from-scratch, button field. I wouldn't necessarily recommend that you do all this yourself, since buttons require focus handling, click handling, etc. You should probably start with something like the BaseButtonField from the BlackBerry AdvancedUI open source library.
I have prototyped this for you, using that class as a base. (so, you'll need to download and include that source file in your project if you use this).
I created a GradientButtonField subclass:
private class GradientButtonField extends BaseButtonField {
private int startR;
private int startG;
private int startB;
private int endR;
private int endG;
private int endB;
/** the maximum distance from the field's center, in pixels */
private double rMax = -1.0;
private int width;
private int height;
private String label;
private int fontColor;
/**
* Create a gradient button field
* #param startColor the integer Color code to use at the button center
* #param endColor the integer Color code to use at the button edges
* #param label the text to show on the button
* #param fontColor color for label text
*/
public GradientButtonField (int startColor, int endColor, String label, int fontColor) {
// record start and end color R/G/B components, to
// make intermediate math easier
startR = (startColor >> 16) & 0xFF;
startG = (startColor >> 8) & 0xFF;
startB = startColor & 0xFF;
endR = (endColor >> 16) & 0xFF;
endG = (endColor >> 8) & 0xFF;
endB = endColor & 0xFF;
this.label = label;
this.fontColor = fontColor;
}
public String getLabel() {
return label;
}
protected void layout(int w, int h) {
width = Math.min(Display.getWidth(), w);
height = Math.min(Display.getHeight(), h);
if (rMax < 0.0) {
rMax = Math.sqrt((width * width)/4.0 + (height * height)/4.0);
}
setExtent(width, height);
}
private int getColor(double scale, boolean highlighted) {
int r = (int)(scale * (endR - startR)) + startR;
int g = (int)(scale * (endG - startG)) + startG;
int b = (int)(scale * (endB - startB)) + startB;
if (highlighted) {
// just brighten the color up a bit
r = (int)Math.min(255, r * 1.5);
g = (int)Math.min(255, g * 1.5);
b = (int)Math.min(255, b * 1.5);
}
return (65536 * r + 256 * g + b);
}
protected void paint(Graphics graphics) {
int oldColor = graphics.getColor();
// we must loop from the outer edge, in, to draw
// concentric circles of decreasing radius, and
// changing color
for (int radius = (int)rMax; radius >= 0; radius--) {
double scale = ((double)radius) / rMax;
boolean focused = (getVisualState() == Field.VISUAL_STATE_FOCUS);
graphics.setColor(getColor(scale, focused));
int x = width / 2 - radius;
int y = height / 2 - radius;
graphics.fillArc(x, y, 2 * radius, 2 * radius, 0, 360);
}
String text = getLabel();
graphics.setColor(fontColor);
graphics.drawText(text,
(width - getFont().getAdvance(text)) / 2,
(height - getFont().getHeight()) / 2);
// reset graphics object
graphics.setColor(oldColor);
}
}
To use this, the Manager that contains the button will need to constrain the button's size in its sublayout() implementation. Or, you can edit my GradientButtonField class to hardcode a certain size (via getPreferredWidth(), layout(), etc.), or whatever you want.
final Field button1 = new GradientButtonField(Color.DARKGRAY, Color.BLUE,
"Click Me!", Color.WHITE);
final Field button2 = new GradientButtonField(Color.DARKGRAY, Color.BLUE,
"Click Me, Too!", Color.WHITE);
Manager mgr = new Manager(Manager.NO_VERTICAL_SCROLL) {
public int getPreferredHeight() {
return Display.getHeight();
}
public int getPreferredWidth() {
return Display.getWidth();
}
protected void sublayout(int maxWidth, int maxHeight) {
setExtent(getPreferredWidth(), getPreferredHeight());
layoutChild(button1, 160, 80);
setPositionChild(button1, 20, 50);
layoutChild(button2, 120, 60);
setPositionChild(button2, 20, 150);
}
};
button1.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
Dialog.alert("clicked!");
}
});
mgr.add(button1);
mgr.add(button2);
add(mgr);
I did not round the corners, as that's a bit of work. Depending on what kind of backgrounds you're putting these buttons on, it might be easiest to create a PNG mask image (in your favorite drawing program), which is mostly transparent, and then just has filled corners that mask off the corners of the gradient below it. Then, use Graphics.drawBitmap() in the paint() method above, after you've drawn the radial gradient.
For focus highlighting, I just put in some simple code to brighten the colors when the button is focused. Again, you didn't say what you wanted for that, so I just did something simple.
Here's the result of the code above. The bottom button is focused:

Set width and height on BlackBerry BitmapField

How do I set width and height of a BitmapField in BlackBerry? The following code works, but I can't show the entire image. The display shows only some portion of my image.
BitmapField bmp = new BitmapField(connectServerForImage(ImageUrl)) {
protected void layout(int width, int height)
{
setExtent(80, 70);
}
};
I assume you're saying that your BitmapField is showing the image you retrieve cropped?
And you would like it to scale, perhaps scaled to fit the size of your BitmapField? There's many ways to do that, but one is to resize the image after downloading, before giving it to the BitmapField:
From this answer on resizing a Bitmap
public static Bitmap resizeImage(Bitmap originalImage, int newWidth, int newHeight) {
Bitmap newImage = new Bitmap(newWidth, newHeight);
originalImage.scaleInto(newImage, Bitmap.FILTER_BILINEAR, Bitmap.SCALE_TO_FILL);
return newImage;
}
(Note that the link I provided has an alternate method for resizing images, if you have to support BlackBerry OS < 5.0).
Then, use
Bitmap img = resizeImage(connectServerForImage(ImageUrl), 80, 70);
BitmapField bmp = new BitmapField(img) {
protected void layout(int width, int height)
{
setExtent(80, 70);
}
};
However, I believe that if you actually set the size of the Bitmap img to 80x70, then there's no need to also set the extent of the BitmapField to 80x70. It should default to the size of the image you give it. So, you could simplify the code to:
BitmapField bmp = new BitmapField(img);
int prefWidth=(30*bitmap.getWidth())/bitmap.getHeight();
Bitmap temp=resizeBitmap(bitmap,prefWidth,30);
where
private 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;
}
This support bb os 4.5

Multiple column list field

I am facing issue while displaying multiple columns in a row. I need multiple columns and multiple row list field. Now I am trying to make this using label field i one of my case its working quite good but in another case I am facing an issue please help me out. My code is:
VerticalFieldManager TOrderVFM = new VerticalFieldManager()
for ( int i = 0; i <10; i++)
{
HorizontalFieldManager temphfm1 = new HorizontalFieldManager(){
protected void sublayout(int width, int height)
{
int w = 480;
int h = 400;
super.sublayout(w, h);
super.setExtent(w, h);
}
};
TOrderVFM.add(temphfm1);
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("orderDate").toString()));
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("id").toString()));
temphfm1.add(.createDayName1(MTradeOrderSoap.objects[i].getProperty("label").toString()));
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("quantityPending").toString()));
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("securityName").toString()));
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("priceType").toString()));
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("orderOrigin").toString()));
temphfm1.add(ut.createDayName1(MTradeOrderSoap.objects[i].getProperty("orderStatus").toString()));
}
This loop is inserting values that are coming from the soap response and passing it to the method named createDayName() which is also given below.Now this all works good for my one of the screens but when i try to follow this for my another screen i am facing an error:-WARNING: Cannot layout field, insufficient height or width
I have set the width and height of both the managers but nothing seems to be working .Please provide me a support to do that.
public LabelField createDayName1(final String day)
{
LabelField cell = new LabelField("", Field.NON_FOCUSABLE) {
protected void layout(int width, int height)
{
int w = Display.getWidth()/7;
int h = 40;
super.layout(w, h);
super.setExtent(w, h);
}
protected void paint(Graphics g)
{
g.setColor(0xFF9912);
g.setFont(dayNameFont);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
// g.setColor(0x466385);
g.drawText(day.trim(), getWidth() / 2 - dayNameFont.getAdvance(day) / 3, getHeight() / 3 - dayNameFont.getHeight() / 2);
super.paint(g);
}
};
return cell;
}
In layout() and sublayout() you need to make sure you're comparing the width and height you are passing to setExtent() (and super.layout()/super.sublayout() for that matter) to the arguments getting sent to those methods because they are the maximum available width and height. If you try to tell the Field to be wider or taller (using setExtent()) than what is available, it won't be able to display properly.

Background image behind two fields in custom HorizontalFieldManager

Below code defines a horizontal field manager with two fields. How can I amend the code so that the background is just set on the two fields being added not on the whole manager. Note, im not attempting to add an individual background image to each of the fields, instead a shared background image that spans behind the two fields.
LabelField label = new LabelField("name");
TextField e = new TextField(Field.FOCUSABLE);
final Bitmap b = Constants.SETTINGS;
final Background bg = BackgroundFactory.createBitmapBackground(Constants.SETTINGS);
HorizontalFieldManager manager = new HorizontalFieldManager()
{
public void sublayout (int width, int height)
{
Field field;
int x = 0;
super.sublayout(b.getWidth(), height);
super.setExtent(b.getWidth(), height);
for (int i = 0; i < getFieldCount(); i++)
{
field = getField(i);
layoutChild(field, Display.getWidth()/2, height);
setPositionChild(field, x, 10);
x += Display.getWidth()/2;
}
}
};
manager.add (label);
manager.add (e);
add (manager);
Rather than putting them in a custom Manager, it may be easier to just override the Fields' layout() calls to be
protected void layout(int width, int height) {
super.layout(width, height);
setExtent(Display.getWidth()/2, this.getHeight());
}
and then you can just use a normal HorizontalFieldManager you can set a background on and a padding (hfm.setPadding(10, 10, 10, 10);). Adding a padding will reduce the available width for your Fields, so you should decrease their widths in the layout() calls.
You can offset each of their individual backgrounds with some fancy, expensive Bitmap footwork (math) to appear to "share" one image using setBackGround(), or you can override their draw methods to achieve the same effect with the ability to "move" across the bitmap according to their relative position...
That what you're after? :)
edit:
create a custom field to use your bitmap and feed it whatever content you would like, then override the paint to draw what you like where you like it...
protected void paint(Graphics g){
// conditionals, etc
g.drawBitmap(x, y, width, height, bitmap, left, top);
// color changes, etc
g.drawText(yourText);
// clean up
}

Blackberry custom button that looks like the default button

I've implemented a custom button using the example code seen here, posted by Bikas:
http://supportforums.blackberry.com/t5/Java-Development/fixedwidth-buttonField-cannot-center-text/m-p/239116
However, I'd like for the button to look like the default Blackberry button.
How would I modify the paint method shown below to look like the default button?
protected void paint(Graphics graphics)
{
int w = width - (leftMargin + rightMargin);
int h = height - (topMargin + bottomMargin);
if(isFocus() == false)
{
graphics.setColor(backgroundColorNormal);
graphics.fillRoundRect(leftMargin, topMargin, w, h, 6, 6);
graphics.setColor(0x00394142);
graphics.drawRoundRect(leftMargin, topMargin, w, h, 6, 6);
graphics.drawText(label, labelTopLeftPoint.x, labelTopLeftPoint.y);
}
else
{
graphics.setColor(backgroundColorOnFocus);
graphics.fillRoundRect(leftMargin, topMargin, w, h, 6, 6);
graphics.drawRoundRect(leftMargin, topMargin, w, h, 6, 6);
graphics.setColor(0x00ffffff);
graphics.drawText(label, labelTopLeftPoint.x, labelTopLeftPoint.y);
}
}
I can't seem to find this information anywhere when searching.
Thank you for your help,
Stateful
In either Eclipse or the legacy JDE, add a unmodified ButtonField to your application, place a breakpoint after you have initialized the object and inspect the details of the unmodified ButtonField to get the properties you need.

Resources