I do not understand what it is that I'm doing wrong, the code seems alright, I am trying to set a background image for a GridLayout, when I add the background code, I get an error, when I comment it out, it runs good in the simulator.. What am I doing wrong?
UPDATE
public class GFMScreen extends MainScreen {
VerticalFieldManager ver;
ButtonField submit;
HorizontalFieldManager hr;
private int phoneWidth = Display.getWidth();
private int cellHeight = Display.getHeight();
public GFMScreen() {
super(Manager.USE_ALL_WIDTH | Manager.NO_VERTICAL_SCROLL);
setTitle("Jonezing");
createGUI();
}
public void createGUI() {
try {
final Bitmap background = Bitmap.getBitmapResource("bg.png");
ver = new VerticalFieldManager(Manager.NO_HORIZONTAL_SCROLL
| VerticalFieldManager.NO_VERTICAL_SCROLL
| Manager.FIELD_VCENTER | USE_ALL_HEIGHT | USE_ALL_WIDTH) {
public void paint(Graphics g) {
Bitmap scaled = new Bitmap(phoneWidth, cellHeight);
background.scaleInto(scaled, Bitmap.SCALE_TO_FIT);
g.drawBitmap(0, 0, phoneWidth, cellHeight, scaled, 0, 0);
super.paint(g);
}
};
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// ver.setBackground(BackgroundFactory.createBitmapBackground(Bitmap
// .getBitmapResource("bg.png")));
ver = new VerticalFieldManager(Manager.NO_HORIZONTAL_SCROLL
| VerticalFieldManager.NO_VERTICAL_SCROLL
| Manager.FIELD_VCENTER | USE_ALL_HEIGHT | USE_ALL_WIDTH);
GridFieldManager grid = new GridFieldManager(4, 2,
Manager.FIELD_VCENTER | Manager.NO_VERTICAL_SCROLL);
grid.add(new BitmapField(Bitmap.getBitmapResource("english.png")));
grid.add(new BitmapField(Bitmap.getBitmapResource("yoruba.png")));
grid.add(new LabelField("English", Field.FOCUSABLE));
grid.add(new LabelField("Yoruba", Field.FOCUSABLE));
grid.add(new BitmapField(Bitmap.getBitmapResource("mp.png")));
grid.add(new BitmapField(Bitmap.getBitmapResource("about.png")));
grid.add(new LabelField("MP3s", Field.FOCUSABLE));
grid.add(new LabelField("About", Field.FOCUSABLE));
grid.setPadding(100, 0, 50, 100);
grid.setColumnPadding(100);
grid.setRowPadding(10);
ver.add(grid);
add(ver);
}
}
Thank you.
There is a possibility that your error is related to GridFieldmanager requiring to be in a non scrolling Manager. So you will get a runtime exception, can't remember what it is, but most likely an IllegalStateException.
I have attempted to use GridFieldManager in the past, and to be honest, I have given up on it, because of problems like this.
As I recommended in your other question here:
blackberry-development-ui
I would stop using GridFieldManager and use TableLayoutManager instead. You can do the same things and if you have any problems with TableLayoutManager, you have the code and can fix it.
If you really want to use GridFieldManager, then find an example of it being used that works, copy that code exactly, and change it bit at a time until you get it to the state you want it.
The other possibility is that the code can't find the background image, in which case you are getting a NullPointerException in the paint() method. Because your problem description is not very good, we can't tell. To check this, just see if the result of this statement:
final Bitmap background = Bitmap.getBitmapResource("bg.png");
has the Bitmap background set to null or not. If it is NOT null, then the image is being found. If it is null, then we need to look for another resolution.
Finally, can I recommend that you do as little processing in paint() as you can. In the paint() method for your VerticalFieldManager, you actually scale the Bitmap every time. Now paint() gets called a lot and scaling is an expensive operation, so I recommend that you rework this code so that you scale the Bitmap only one.
Sorry one more thing - you may need to be careful about image scaling. You are scaling an image to match the size of the screen - what if that screen is landscape or portrait? Will the image become distorted?
Update
I have just noted a couple of other things with this code:
try {
final Bitmap background = Bitmap.getBitmapResource("bg.png");
ver = new VerticalFieldManager(Manager.NO_HORIZONTAL_SCROLL
| VerticalFieldManager.NO_VERTICAL_SCROLL
| Manager.FIELD_VCENTER | USE_ALL_HEIGHT | USE_ALL_WIDTH) {
public void paint(Graphics g) {
Bitmap scaled = new Bitmap(phoneWidth, cellHeight);
background.scaleInto(scaled, Bitmap.SCALE_TO_FIT);
g.drawBitmap(0, 0, phoneWidth, cellHeight, scaled, 0, 0);
super.paint(g);
}
};
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
1) In this code, the try/catch is only catching errors in the creation of the bitmap and the VFM. It does not catch any errors in the paint() method. I doubt very much that you are getting an error in the constructions of either the bitmap or the VFM
2) The e.printStackTrace(); will not produce a stack trace, in fact in this case I doubt that it will do anything at all, except mask a problem. The only way to get a stack trace in BB java is to catch Throwable. the code you probably want to use goes like this:
try {
....
} catch (Throwable t) {
t.printStackTrace();
}
Use try catch blocks
try{
//your back ground code here
}
catch(Exception e){
}
Related
I am calling this class which is PopupScreen.
public class Custom_LoadingScreen extends PopupScreen {
private VerticalFieldManager vfm;
private Util_AnimateGifField anmtFldCycle = null;
private GIFEncodedImage gifImgCycle;
public Custom_LoadingScreen() {
super(new VerticalFieldManager());
Background bg = BackgroundFactory.createSolidTransparentBackground(
Color.BLACK, 190);
setBackground(bg);
setBorder(BorderFactory.createSimpleBorder(new XYEdges(),
Border.STYLE_TRANSPARENT));
gifImgCycle = (GIFEncodedImage) GIFEncodedImage
.getEncodedImageResource("LoadingSpinner.gif");
anmtFldCycle = new Util_AnimateGifField(gifImgCycle,
Field.FIELD_HCENTER);
vfm = new VerticalFieldManager(USE_ALL_WIDTH) {
protected void sublayout(int maxWidth, int maxHeight) {
super.sublayout(Display.getWidth(), Display.getHeight());
setExtent(Display.getWidth(), Display.getHeight());
}
};
int padding = (Display.getHeight() - 16) / 2;
if (padding > 0) {
anmtFldCycle.setPadding(padding, 0, 0, 0);
}
vfm.add(anmtFldCycle);
add(vfm);
}
//public void Popupscreen() {
//Main.getUiApplication().popScreen(this);
//}
public boolean keyDown(int keycode, int status) {
if (Keypad.key(keycode) == Keypad.KEY_ESCAPE) {
Main.getUiApplication().popScreen(this);
return true;
}
return super.keyDown(keycode, status);
}
}
In a button, I pushed it before goes to next screen.
financebtn = new Custom_ButtonField(finance, financeactive,
financeactive) {
protected boolean navigationClick(int status, int time) {
Main.getUiApplication().pushScreen(new Custom_LoadingScreen());
Main.getUiApplication().invokeLater(new Runnable() {
public void run() {
// Main.getUiApplication().popScreen();
Main.getUiApplication().pushScreen(
new Main_NewsDetail());
}
}, 1 * 1000, false);
return true;
}
};
add(financebtn);
The result give me Uncaught:ClassCastException. I can call another class which is similar to custom_loadingscreen also popupscreen. It work fine.
I also tried call this class in another button yet still same problem.
If you take a look at your Custom_LoadingScreen code, there's only one place where you are doing a cast:
gifImgCycle = (GIFEncodedImage) GIFEncodedImage
.getEncodedImageResource("LoadingSpinner.gif");
So, that's a good place to start looking. If you Google for "BlackBerry GIFEncodedImage ClassCastException", you'll find this thread:
http://supportforums.blackberry.com/t5/Java-Development/GIFEncodedImage-in-BlackBerry-OS7/td-p/1228959
The problem is that, for optimization, BlackBerry likes to convert images to the PNG format, which most smartphones work best with. So, what's happening here is that your GIF image is actually being converted to a PNG image. Therefore, when you call the getEncodedImageResource() method, the object you are getting back may actually be of type PNGEncodedImage, not GIFEncodedImage, and you get the exception. Sneaky, huh?
You can solve it a few ways.
In the Blackberry_App_Descriptor.xml file, you can uncheck the setting that specifies that images are converted to PNG (Build tab -> Convert image files to png)
You can trick the build system by renaming your GIF file to something like LoadingSpinner.agif. The toolset doesn't recognize the .agif extension, and therefore won't try to convert it. If you do this, of course, remember to change the filename in your Java code, too, when loading it.
You can change the code to use PNGEncodedImage, or test the object like this:
EncodedImage img = EncodedImage.getEncodedImageResource("LoadingSpinner.gif");
if (img instanceof GIFEncodedImage) {
// cast to GIFEncodedImage
} else if (img instanceof PNGEncodedImage) {
// cast to PNGEncodedImage
}
Number (1) will lose the non-PNG to PNG conversion optimization for all your non-PNG images, not just this one.
Number (2) does look a little ugly. The benefit of doing this, though, is that you can disable this behaviour for just this one image. If most of your images are not PNG images, it might be valuable to let BlackBerry optimize for you, for the other images. But, maybe this one needs to be a GIF. So, #2 lets you handle this one as a special case.
I'm just guessing that this image might be an animated GIF? Is that right? If so, you probably want to keep it as a GIF, so you won't want to do number (3), which lets it be converted to a PNG, and uses it as such.
So, I'm working on my paint application. Every time I make changes, the current screen state is copied and saved as a bitmap image on my disk (so I can use it in my paint event).
The problem occurs when I minimize and return the window to its normal state and then try to draw. This triggers my event reacting to changes, the program tries to save the image ---->>> kabooom.
It says "A generic error occurred in GDI+".. So, I've been surfing through various forums in search for the answer but none of them gave me true answer, they all mention wrong paths etc. but I'm pretty sure that's not the problem. Do I have to dispose bitmap or do something with the stream?
int width = pictureBox1.Size.Width;
int height = pictureBox1.Size.Height;
Point labelOrigin = new Point(0, 0); // this is referencing the control
Point screenOrigin = pictureBox1.PointToScreen(labelOrigin);
int x = screenOrigin.X;
int y = screenOrigin.Y;
Rectangle bounds = this.Bounds;
using (Bitmap bitmap = new Bitmap(width, height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(new Point(x, y), Point.Empty, bounds.Size);
}
bitmap.Save(_brojFormi + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
}
You're saving an image to disk so you can use it in another event? Wow.
Why not just use a class-global variable to store the bitmap?
class MyForm
{
Bitmap currentImage = null;
Graphics gfx = null;
private void btnLoad_Click(object sender, EventArgs e)
{
// ...
currentImage = new Bitmap(fileName);
gfx = Graphics.FromImage(currentImage);
}
private void pbEditor_Paint(object sender, PaintEventArgs e)
{
if (currentImage != null && gfx != null)
{
lock(currentImage) e.Graphics.DrawImage(currentImage, ...);
}
}
private void pbEditor_Click(object sender, MouseEventArgs e)
{
// quick example to show bitmap drawing
if (e.Button == MouseButtons.Left)
lock(currentImage) currentImage.SetPixel(e.Location.X, e.Location.Y, Colors.Black);
}
}
I want to create an editfield whose cursor keeps at righthandside of it.
To illustrate if i want to write "blackberry", result should be like this.
<-----------width-of-editfield------>
b
bl
bla
blac
black
blackb
blackbe
blackber
blackberr
blackberry
Thanks
Because of non-sense of lack of reputation thing, i can not answer my own question.
Any way, I found an easy way. width refers to width of the manager which holds this edit field.
editField = new EditField("","",maxChars,EditField.NO_NEWLINE | EditField.NON_SPELLCHECKABLE){
protected boolean keyChar(char key, int status, int time) {
editField.setPadding(0, 0, 0, width - (getFont().getAdvance(this.getText())) - 10);
invalidate();
return super.keyChar(key, status, time);
}
};
You will have to create your own Manager, unfortunately. There is no simple or obvious way to do this.
A solution with source code was posted on the BlackBerry forums.
Just like Swati's solution. I did like this:
editField = new EditField("", "", maxChars, EditField.NO_NEWLINE | EditField.NON_SPELLCHECKABLE){
protected boolean keyChar(char key, int status, int time){
switch (key){
case Characters.BACKSPACE:{
try {
text = text.substring(0,text.length()-1);
invalidate();
} catch (IndexOutOfBoundsException e) {}
return true;
}
}
text = text + key;
invalidate();
return true;
}
protected void paint(Graphics graphics) {
graphics.drawText(text,0, 0, DrawStyle.RIGHT, width - 10);
super.paint(graphics);
}
};
I've managed to get images into a custom drawListRow:
public void drawListRow(ListField listField, Graphics graphics, int index, int y, int width) {
graphics.drawBitmap(0, (index) * listField.getRowHeight(), firstrowPostion, rowHeight, thing.image, 0, 0);
graphics.setFont(titleFont);
graphics.drawText(thing.title, firstrowPostion, y, (DrawStyle.LEFT | DrawStyle.ELLIPSIS | DrawStyle.TOP ), 250);
}
The first time though everything works perfectly but once I get to the bottom of the list and start to scroll up again, the pictures have disappeared.
Any suggestions?
Edit: I've figured out the second time through this code:
try {
InputStream inputStream = Connector.openInputStream(ImagePath);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
int i = 0;
while ((i = inputStream.read()) != -1) {
outputStream.write(i);
}
byte[] data = outputStream.toByteArray();
EncodedImage eimg = EncodedImage.createEncodedImage(data, 0,
data.length);
Bitmap image = eimg.getBitmap();
inputStream.close();
outputStream.close();
return ImageUtility.resizeBitmap(image, 70, 70);
} catch (IOException e) {
return null;
} catch (IllegalArgumentException ex) {
return null;
}
}
that InputStream inputStream = Connector.openInputStream(ImagePath); is throwing an IOException. I understand from here
that IO will be thrown under these conditions: but I don't know which is the cause:
1. more than one openInputStream() on single instance of fileconnection.
2. openInputStream() on already closed fileconnection.
3. openInputStream() on a directory.
again any suggestions?
I figured out it's best to just create a separate array of fully formed images and send both that and the thing array to drawlistrow, instead of trying to form and draw them as every row is drawn.
I'm trying to have a full screen UI with a fix header ( a manager with some fields) and a scrollable contents (a list of custom field). The idea is to emulate a kind of scrollable list.
For this I made a custom VerticalFieldManager that accept a maxHeight (the screen height - the header height).
I got the following problems:
The scroll arrows do not show up (ever)
On OS 4.7 (Storm), I can scroll lower that the last item, until having nothing on my screen but the header.
My code need to compile with the JDE 4.2.1 & 4.7 and to run on Pearl and Storm. (at worst I could have two version of this class)
I suspect the two problems are related. I probably do something wrong. I looked at a few example/forum and always found similar solution/code.
Do you guys can tell me what I did wrong?
/**
* custom class, so we can set a max height (to keep the header visible)
*/
class myVerticalFieldManager extends VerticalFieldManager{
private int maxHeight = 0;
myVerticalFieldManager(int _maxHeight){
super(
//this provoc an "empty scrollable zone" on Storm
// but if you don't put it, on other OS, the vertical manager does not scroll at all.
Manager.VERTICAL_SCROLL
| Manager.VERTICAL_SCROLLBAR
);
maxHeight = _maxHeight;
}
protected void sublayout(int width, int height){
super.sublayout(width, getPreferredHeight());
setExtent(width, getPreferredHeight());
}
public int getPreferredWidth() {
return Graphics.getScreenWidth();
}
/**
* allow the manager to use all the given height. (vs auto Height)
*/
public boolean forceMaxHeight = false;
public int getPreferredHeight() {
if (forceMaxHeight) return maxHeight;
int m = super.getPreferredHeight();
if (m > maxHeight) m = maxHeight;
return m;
}
////////////////////////////////////////////////////////////////////////////
protected boolean isUpArrowShown(){
//TODO: does not seem to work (4.2.1 emulator & 4.5 device). (called with good return value but the arrows are not painted)
int i = getFieldWithFocusIndex();
//Trace("isUpArrowShown " + i);
return i > 0;
// note: algo not correct, cause the up arrow will be visible event when no field are hidden.
// but not so bad, so the user "know" that he can go up.
}
protected boolean isDownArrowShown(){
int i = getFieldWithFocusIndex();
return i < getFieldCount();
}
////////////////////////////////////////////////////////////////////////////
// note : since 4.6 you can use
// http://www.blackberry.com/developers/docs/4.6.0api/net/rim/device/api/ui/decor/Background.html
public int myBackgroundColor = 0xffffff;
protected void paint(Graphics g){
g.setBackgroundColor(myBackgroundColor);
// Clears the entire graphic area to the current background
g.clear();
super.paint(g);
}
}
any helps is welcome.
so,
I came with this workaround for the "empty scrollable zone" problem on STORM
it's ugly and doesn't allow a custom ScrollChangeListener, but it's working on Pearl & Storm
implements ScrollChangeListener
//in constructor:
setScrollListener(null);
setScrollListener(this);
private boolean MY_CHANGING_SCROLL = false;
public void scrollChanged(Manager manager, int newHorizontalScroll, int newVerticalScroll){
if (!MY_CHANGING_SCROLL){
MY_CHANGING_SCROLL = true;
myCheckVerticalScroll();
MY_CHANGING_SCROLL = false;
}
}
protected int myMaxVerticalScrollPosition(){
int vh = getVirtualHeight();
int h = getHeight();
if (vh < h ) return 0; // no scroll
return vh - h; // don't scroll lower than limit.
}
protected void invCheckVerticalScroll() {
int i = getVerticalScroll();
int m = myMaxVerticalScrollPosition();
if ( i > m){
i = m;
setVerticalScroll(i);
}
}
I'm still looking for a solution to the scroll arrows problem...
If anybody got an idea...
You can use the method setBanner() instead of add for your header. Then you can add a default VerticalFieldManager to the screen and it will scroll normally but won't hide the header. Note that the MainScreen delegate manager is a VerticalScrollManager so you might not need a second vfm.
HorizontalFieldManager hfm = new HorizontalFieldManager();
setBanner(hfm)
add(new ButtonField("Hello 1");
add(new ButtonField("Hello 2");
...
Hey i did the same thing using a HorizontalFieldManager that contains an image and a title
header_img = Bitmap.getBitmapResource("header.png");
title = new LabelField("Welcome",LabelField.FIELD_RIGHT);
header_manager = new HorizontalFieldManager()
{
protected void paint(net.rim.device.api.ui.Graphics graphics)
{
int y = this.getVerticalScroll();
graphics.drawBitmap( 0, y, header_img.getWidth(), header_img.getHeight(), header_img, 0, 0 );
graphics.setColor(Color.LEMONCHIFFON);
super.paint( graphics );
}
protected void sublayout(int maxWidth, int maxHeight)
{
super.sublayout(Display.getWidth(), 240);
Field field = title;
layoutChild(field, title.getWidth(), title.getHeight());
setPositionChild(field, (Display.getWidth()/2) -10, 13);
setExtent(Display.getWidth(),55);
}
};
header_manager.add(title);