Blackberry custom button that looks like the default button - blackberry

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.

Related

Graphics drawing code generates blank images, only on iOS

My app displays some images that I created using Image.createImage(). In some cases, the images are completely blank, but only on iOS. The images work fine on Android. Also, I create several images using Image.createImage() and most of them work fine. I don't see any difference between those and these.
To reproduce, run the enclosed app on both Android and iOS. The app shows two images. The second one is taken from the bottom half of the first one. On Android, the images show up fine. On iOS, the images show up for a few seconds, then vanish. It turns out that they only show up while iOS is displaying the startup screen. Once it switches to the actual app, the images are blank, although they take up the same space. Further tests reveal that the images are the correct size but are filled with transparent pixels.
I should say that, in my actual application, the images scale with the size of the screen, and are colored according to a user preference, so I can't just load them from a resource.
(BTW Notice the change I made to the stop method. This is unrelated but worth mentioning.)
Here's the test case:
import com.codename1.ui.Component;
import com.codename1.ui.Container;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.ui.Dialog;
import com.codename1.ui.Graphics;
import com.codename1.ui.Image;
import com.codename1.ui.Label;
import com.codename1.ui.layouts.BorderLayout;
import com.codename1.ui.layouts.BoxLayout;
import com.codename1.ui.plaf.UIManager;
import com.codename1.ui.util.Resources;
import com.codename1.io.Log;
import com.codename1.ui.Toolbar;
import java.util.Arrays;
/**
* This file was generated by Codename One for the purpose
* of building native mobile applications using Java.
*/
#SuppressWarnings("unused")
public class HalfImageBug {
private Form current;
private Resources theme;
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
}
public void start() {
if (current != null) {
current.show();
return;
}
Form hi = new Form("Hi World", new BorderLayout());
hi.addComponent(BorderLayout.CENTER, makeComponent());
hi.show();
}
public void stop() {
current = Display.getInstance().getCurrent();
// This was originally if, but it should be while, in case there are multiple layers of dialogs.
while (current instanceof Dialog) {
((Dialog) current).dispose();
current = Display.getInstance().getCurrent();
}
}
public void destroy() {
}
private Component makeComponent() {
final Container container = new Container(new BoxLayout(BoxLayout.Y_AXIS));
container.setScrollableY(true);
container.add(new Label("Full Image:"));
Image fullIcon = createFullImage(0x44ff00, 40, 30);
Label fullImage = new Label(fullIcon);
container.add(fullImage);
container.add(new Label("---"));
container.add(new Label("Half Image:"));
Image halfIcon = createHalfSizeImage(fullIcon);
Label halfImage = new Label(halfIcon);
container.add(halfImage);
return container;
}
private Image createFullImage(int color, int verticalDiameter, int horizontalRadius) {
// Make sure it's an even number. Otherwise the half image will have its right and left halves reversed!
int diameter = (verticalDiameter / 2) * 2;
final int iconWidth = 2 * horizontalRadius;
int imageWidth = iconWidth + 2;
int imageHt = diameter + 2;
Image fullImage = Image.createImage(imageWidth, imageHt);
Graphics g = fullImage.getGraphics();
g.setAntiAliased(true);
g.setColor(color);
g.fillRect(0, 0, imageWidth, imageHt);
g.setColor(darken(color, 25));
g.fillArc(1, 1, iconWidth, diameter, 180, 360);
g.setColor(0xbfbfbf);
final int smallerHt = (9 * diameter) / 10;
g.fillArc(0, 0, iconWidth, smallerHt, 180, 360);
Image maskImage = Image.createImage(imageWidth, imageHt);
g = maskImage.getGraphics();
g.setAntiAliased(true);
g.setColor(0);
g.fillRect(0, 0, imageWidth, imageHt);
g.setColor(0xFF);
g.fillArc(1, 1, iconWidth, diameter, 180, 360);
fullImage = fullImage.applyMask(maskImage.createMask());
return fullImage;
}
private Image createHalfSizeImage(Image fullImage) {
int imageWidth = fullImage.getWidth();
int imageHt = fullImage.getHeight();
int[] rgbValues = fullImage.getRGB();
// yeah, I've since discovered a much more sensible way to do this, but it doesn't fix the bug.
int[] bottomHalf = Arrays.copyOfRange(rgbValues, rgbValues.length / 2, rgbValues.length);
//noinspection StringConcatenation
Log.p("Cutting side image from " + imageWidth + " x " + imageHt + " to " + imageWidth + " x " + (imageHt / 2));
return Image.createImage(bottomHalf, imageWidth, imageHt / 2);
}
private static int darken(int color, int percent) {
if ((percent > 100) || (percent < 0)) {
throw new IllegalArgumentException("Percent out of range: " + percent);
}
int percentRemaining = 100 - percent;
return (darkenPrimary((color & 0xFF0000) >> 16, percentRemaining) << 16)
| (darkenPrimary((color & 0xFF00) >> 8, percentRemaining) << 8)
| (darkenPrimary(color & 0xFF, percentRemaining));
}
private static int darkenPrimary(int primaryValue, int percentRemaining) {
if ((primaryValue < 0) || (primaryValue > 255)) {
throw new IllegalArgumentException("Primary value out of range (0-255): " + primaryValue);
}
return (primaryValue * percentRemaining) / 100;
}
}
This is discussed in this issue.
Generally the images initially appear because of the screenshot process that shows them so they never really show up on iOS natively.
A common cause for these issues is creating images off of the EDT which doesn't seem to be the issue in this specific code.
It's hard to see what is going on so I guess we'll need to evaluate the issue.
Here's a workaround. This works, but doesn't anti-alias very well. It will do until the iOS code gets fixed.
The problem is as described elsewhere. The Graphics.fillArc() and drawArc() methods work fine on Android, but often fail on iOS. Here's the behavior:
if width == height, they correctly draw a circle.
if width < height, they should draw an ellipse, but they draws a circle, centered over the intended ellipse, with a diameter equal to width.
if width > height, they draw nothing.
The workaround draws a circle against a transparent background, then draws that circle, squeezed in one direction to an ellipse, into the proper place. It doesn't do a very good job of anti-aliasing, so this is not a good substitute for working code, but it will do until the bug gets fixed. (This workaround handles fillArc, but it shouldn't be hard to modify it for drawArc()
/**
* Workaround for fillArc bug. Graphics.fillArc() works fine on android, but usually fails on iOS. There are three
* cases for its behavior.
*
* If width < height, it draws a circle with a diameter equal to width, and concentric with the intended ellipse.<br>
* If width > height, it draws nothing.<br>
* If width == height, it works correctly.
*
* To work around this we create a separate image, draw a circle, re-proportion it to the proper ellipse, then draw
* it to the Graphics object. It doesn't anti-alias very well.
*/
public static void fillArcWorkaround(Graphics masterG, int x, int y, int width, int height, int startAngle, int arcAngle) {
if (width == height) {
masterG.fillArc(x, y, width, height, startAngle, arcAngle);
} else {
int max = Math.max(width, height);
Image tempCircle = Image.createImage(max, max);
Graphics tempG = tempCircle.getGraphics();
tempG.setColor(masterG.getColor());
tempG.fillRect(0, 0, max, max);
// At this point tempCircle is just a colored rectangle. It becomes a circle when we apply the circle mask. The
// region outside the circle becomes transparent that way.
Image mask = Image.createImage(max, max);
tempG = mask.getGraphics();
tempG.setAntiAliased(masterG.isAntiAliased());
tempG.setColor(0);
tempG.fillRect(0, 0, max, max);
tempG.setColor(0xFF); // blue
tempG.fillArc(0, 0, max, max, startAngle, arcAngle);
tempCircle = tempCircle.applyMask(mask.createMask());
// Now tempCircle is a filled circle of the correct color. We now draw it in its intended proportions.
masterG.setAntiAliased(true);
masterG.drawImage(tempCircle, x, y, width, height);
}
}

Unable to display image from web on blackberry device

I developed simple code to display an image and title on blackberry screen, but I am not able to display anything (but if I tested for title only it is working).
My requirement is to display image with title in a list.
I have followed this link for fetching image from image url
and here my code in drawlistrow method:
public void drawListRow(ListField list, Graphics g, int index, int y, int w)
{
String text = (String)listElements.elementAt(index);
Bitmap image =GetImage.connectServerForImage("http://toucheradio.com/toneradio/iphone/toriLite/toriLive.png");
g.drawLine(0, y, w, y);
g.drawText(text, 150, y, 60, w);
g.drawBitmap(0,y,image.getWidth(),image.getHeight(),image,0,0);
}
What could be the problem?
And please check the image height and width if its big than your screen resolution, then you have to crop or enlarge the image you are getting. Give some x axis to the drawBitmapMethod i have just giving you the idea like below you can implement.
g.drawBitmap(340, y, image.getWidth(), image.getHeight(), image, 0, 0);

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 RichTextField preferred height during layout

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.

Resources