Tuesday, July 28, 2009

Writing Custom TextBox in Blackberry

Something it is required to write customized TextBox because using native API you cannot get the border, backgound color, backgroung image, left shift characters when text are more than one line without customizing.

In such type of cases you can create a Class extending Field
and the following things have to override:
* sublayout()
* paint()
* getPreferredWidth()
* getPreferredHeight()

The below Class demonstrate the above implementation:

import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.system.Characters;
import net.rim.device.api.math.Fixed32;
import net.rim.device.api.ui.DrawStyle;
import net.rim.device.api.ui.Font;

public class CustomTextBox extends Manager
{
/**
* Default margins
*/
private final static int DEFAULT_LEFT_MARGIN = 10;
private final static int DEFAULT_RIGHT_MARGIN = 10;
private final static int DEFAULT_TOP_MARGIN = 5;
private final static int DEFAULT_BOTTOM_MARGIN = 5;

/**
* Default paddings
*/
private final static int DEFAULT_LEFT_PADDING = 10;
private final static int DEFAULT_RIGHT_PADDING = 10;
private final static int DEFAULT_TOP_PADDING = 5;
private final static int DEFAULT_BOTTOM_PADDING = 5;

/**
* Margins around the text box
*/
private int topMargin = DEFAULT_TOP_MARGIN;
private int bottomMargin = DEFAULT_BOTTOM_MARGIN;
private int leftMargin = DEFAULT_LEFT_MARGIN;
private int rightMargin = DEFAULT_RIGHT_MARGIN;

/**
* Padding around the text box
*/
private int topPadding = DEFAULT_TOP_PADDING;
private int bottomPadding = DEFAULT_BOTTOM_PADDING;
private int leftPadding = DEFAULT_LEFT_PADDING;
private int rightPadding = DEFAULT_RIGHT_PADDING;

/**
* Amount of empty space horizontally around the text box
*/
private int totalHorizontalEmptySpace = leftMargin + leftPadding
+ rightPadding + rightMargin;

/**
* Amount of empty space vertically around the text box
*/
private int totalVerticalEmptySpace = topMargin + topPadding
+ bottomPadding + bottomMargin;

/**
* Minimum height of the text box required to display the text entered
*/
private int minHeight = getFont().getHeight() + totalVerticalEmptySpace;

/**
* Width of the text box
*/
private int width = Display.getWidth();

/**
* Height of the text box
*/
private int height = minHeight;

/**
* Background image for the text box
*/
private EncodedImage backgroundImage;

/**
* Bitmap version of the backgroundImage.
* Needed to reduce the calculation overhead incurred by
* scaling of the given image
* and derivation of Bitmap from the
* EncodedImage every time it is needed.
*/
private Bitmap bitmapBackgroundImage;

/**
* The core element of this text box
*/
private EditField editField;
//private BasicEditField editField;

//private String entireText;

public CustomTextBox()
{
// Let the super class initialize the core
super(0);

// An edit field is the sole field of this manager.
editField = new EditField();
//editField = new CustomEditField();
add(editField);
}

public CustomTextBox(EncodedImage backgroundImage)
{
this();
setBackgroundImage(backgroundImage);
}

public void setSize(int width, int height)
{
boolean isChanged = false;

if (width > 0 // Ignore invalid width
&& this.width != width)
{
this.width = width;
isChanged = true;
}

// Ignore the specified height if it is less
// than the minimum height required to display the text.
if (height > minHeight && height != this.height)
{
this.height = height;
isChanged = true;
}

// If width/height has been changed and background image
// is available, adapt it to the new dimension
if (isChanged == true && backgroundImage != null)
{
bitmapBackgroundImage = getScaledBitmapImage(backgroundImage,
this.width - (leftMargin+rightMargin),
this.height - (topMargin+bottomMargin));
}
}

public void setWidth(int width)
{

if (width > 0 && width != this.width)
{
this.width = width;

// If background image is available, adapt it to the new width
if (backgroundImage != null)
{
bitmapBackgroundImage = getScaledBitmapImage(backgroundImage,
this.width - (leftMargin+rightMargin),
this.height - (topMargin+bottomMargin));
}
}
}

public void setHeight(int height)
{
// Ignore the specified height if it is
// less than the minimum height required to display the text.
if (height > minHeight)
{
this.height = height;

// If background image is available, adapt it to the new width
if (backgroundImage != null)
{
bitmapBackgroundImage = getScaledBitmapImage(backgroundImage,
this.width - (leftMargin+rightMargin),
this.height - (topMargin+bottomMargin));
}
}
}

public void setBackgroundImage(EncodedImage backgroundImage)
{
this.backgroundImage = backgroundImage;

// Consider the height of background image in
// calculating the height of the text box.
// setHeight() does not ensure that specified
// height will be in effect, of course, for valid reasons.
// So derivation of Bitmap image in the setHeight() method is not sure.
setHeight(backgroundImage.getHeight() + topMargin + bottomMargin);
if (bitmapBackgroundImage == null)
{
bitmapBackgroundImage = getScaledBitmapImage(backgroundImage,
this.width - (leftMargin+rightMargin),
this.height - (topMargin+bottomMargin));
}
}

/**
* Generate and return a Bitmap Image scaled according
* to the specified width and height.
*
* @param image EncodedImage object
* @param width Intended width of the returned Bitmap object
* @param height Intended height of the returned Bitmap object
* @return Bitmap object
*/
private Bitmap getScaledBitmapImage(EncodedImage image, int width, int height)
{
// Handle null image
if (image == null)
{
return null;
}

int currentWidthFixed32 = Fixed32.toFP(image.getWidth());
int currentHeightFixed32 = Fixed32.toFP(image.getHeight());

int requiredWidthFixed32 = Fixed32.toFP(width);
int requiredHeightFixed32 = Fixed32.toFP(height);

int scaleXFixed32 = Fixed32.div(currentWidthFixed32, requiredWidthFixed32);
int scaleYFixed32 = Fixed32.div(currentHeightFixed32, requiredHeightFixed32);

image = image.scaleImage32(scaleXFixed32, scaleYFixed32);

return image.getBitmap();
}


protected void sublayout(int width, int height)
{
// We have one and only child - the edit field.
// Place it at the appropriate place.
Field field = getField(0);
layoutChild(field, this.width - totalHorizontalEmptySpace,
this.height - totalVerticalEmptySpace);
setPositionChild(field, leftMargin+leftPadding, topMargin+topPadding);

setExtent(this.width, this.height);
}

public void setTopMargin(int topMargin)
{
this.topMargin = topMargin;
}

public void setBottomMargin(int bottomMargin)
{
this.bottomMargin = bottomMargin;
}


protected void paint(Graphics graphics)
{
// Draw background image if available, otherwise draw a rectangle
if (bitmapBackgroundImage == null)
{
//graphics.drawRect(leftMargin, topMargin,
width - (leftMargin+rightMargin),
height - (topMargin+bottomMargin));
graphics.drawRoundRect(leftMargin, topMargin,
width - (leftMargin+rightMargin),
height - (topMargin+bottomMargin), 5, 5);
}
else
{
graphics.drawBitmap(leftMargin, topMargin,
width - (leftMargin+rightMargin),
height - (topMargin+bottomMargin),
bitmapBackgroundImage, 0, 0);
}

// Determine the rightward text that can fit into the visible edit field

EditField ef = (EditField)getField(0);
String entireText = ef.getText();

boolean longText = false;
String textToDraw = "";
Font font = getFont();
int availableWidth = width - totalHorizontalEmptySpace;
if (font.getAdvance(entireText) <= availableWidth)
{
textToDraw = entireText;
}
else
{
int endIndex = entireText.length();
for (int beginIndex = 1; beginIndex < endIndex; beginIndex++)
{
textToDraw = entireText.substring(beginIndex);
if (font.getAdvance(textToDraw) <= availableWidth)
{
longText = true;
break;
}
}
}

if (longText == true)
{
// Force the edit field display only the truncated text
ef.setText(textToDraw);

// Now let the components draw themselves
super.paint(graphics);

// Return the text field its original text
ef.setText(entireText);
}
else
{
super.paint(graphics);
}
}

public int getPreferredWidth()
{
return width;
}

public int getPreferredHeight()
{
return height;
}

protected boolean keyChar(char ch, int status, int time)
{
if (ch == Characters.ENTER)
{
return true;
}
else
{
return super.keyChar(ch, status, time);
}
}

public String getText()
{
return ((EditField)getField(0)).getText();
}

public void setText(final String text)
{
((EditField)getField(0)).setText(text);
}
}



Monday, July 27, 2009

Title Bar in Blackberry



The common approach of setting title in BB scrren is like:
setTitle(Field)

But problem of using setTitle method is the border color that you cannot remove.
This is associated with the device theme.

Then one have to write his own title bar.

The following TitleBar has the below properties:
* background color is black
* title image is placed horizontal center
* title bar height is same as the height of the title image


import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;


/**
* customized Title Bar
* background color is black (BACKGROUND_COLOR)
* image is placed horizontal center (titleImage)
* title bar height is same as the height of the title image (fieldHeight)
*/
public class TitleBar extends Field implements DrawStyle
{
private int fieldWidth;
private int fieldHeight;
private int fontColour;
private int backgroundColor;

private Bitmap titleImage = Bitmap.getBitmapResource("topBannerTransparent.png");
private static final int BACKGROUND_COLOR = 0x00000000;


public TitleBar()
{
super(Field.NON_FOCUSABLE);
fieldHeight = titleImage.getHeight();
fieldWidth = Graphics.getScreenWidth();

//background color is black
backgroundColor = BACKGROUND_COLOR;
}

public void setBackgroundColour(int _backgroundColour)
{
backgroundColor = _backgroundColour;
invalidate();
}

protected void layout(int width, int height)
{
setExtent(getPreferredWidth(), getPreferredHeight());
}

public int getPreferredWidth()
{
return fieldWidth;
}

public int getPreferredHeight()
{
return fieldHeight;
}

protected void paint(Graphics graphics)
{

int w = this.getPreferredWidth();
int h = this.getPreferredHeight();

graphics.setColor(backgroundColor);
graphics.fillRect(0, 0, w, h);

int marginX = (w- titleImage.getWidth() ) / 2 ;
graphics.drawBitmap(marginX, 0, w, h, titleImage, 0, 0);
}
}


To make this TitleBar treat like original title bar( always visible in the top) the main scrren have to modify like below:

import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;

class TitleBarExampleScreen extends MainScreen
{
TitleBar titleBar = new TitleBar();
int titleBarHeight = titleBar.getPreferredHeight();

public TitleBarExampleScreen()
{

super(NO_VERTICAL_SCROLL);

//title Bar added here
this.add(titleBar);


VerticalFieldManager verticalManager = new VerticalFieldManager(Manager.VERTICAL_SCROLL | Manager.VERTICAL_SCROLLBAR )
{
public void paint(Graphics graphics)
{
graphics.setBackgroundColor(0x00000000);
graphics.clear();
super.paint(graphics);
}
protected void sublayout( int maxWidth, int maxHeight )
{
int displayWidth = Display.getWidth();
int displayHeight = Display.getHeight() - titleBarHeight;

super.sublayout( displayWidth, displayHeight);
setExtent( displayWidth, displayHeight);
}
};

//now add everything in the verticalManager
verticalManager.add(new LabelField("Test Label"));
verticalManager.add(new ButtonField("Test Button"));

//and at last add verticalManager in scereen
this.add(verticalManager);
}
}



Thursday, July 23, 2009

How to Read, Write and Copy file in Blackberry

It is very common feature in Blackberry to read/write/copy file programatically in BlackBerry.

Read file in the SDCard in the following way:

InputStream inputStream = null;
FileConnection fileConnection = (FileConnection) Connector.open( "file:///SDCard/testfile.txt");
if (fileConnection.exists())
{
inputStream = fconn.openInputStream();
}


ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
while (true) {
int bytesRead = inputStream.read( buffer, 0, BUFFER_SIZE );
if (bytesRead == -1)
break;
byteArrayOutputStream.write( buffer, 0, bytesRead );
}
byteArrayOutputStream.flush();
byte[] result = byteArrayOutputStream.toByteArray();
byteArrayOutputStream.close();
String resultString = new String(result);



Write/Save file in SDCard in the following way:

FileConnection fc = (FileConnection) Connector.open(System.getProperty("file:///SDCard/"+"fileName.txt"),Connector.READ_WRITE);
if(!fc.exists())
{
fc.create();
}
OutputStream os =fc.openOutputStream();
os.write("Test");
os.close();
fc.close()




Copy file in SDCard in the following way:

public static void copyFile(String srFile, String dtFile)
{
try
{
FileConnection f1;
FileConnection f2;

f1 = (FileConnection) Connector.open(srFile,Connector.READ_WRITE);
f2 = (FileConnection) Connector.open(dtFile,Connector.READ_WRITE);
if(!f2.exists()) // if file does not exists , create a new one
{
f2.create();
}
InputStream is = f1.openInputStream();
OutputStream os =f2.openOutputStream();
byte[] buf = new byte[1024];
int len;
while ((len = is.read(buf)) > 0)
{
os.write(buf, 0, len);
}
is.close();
os.close();
}
catch(IOException e)
{

}
}



Also check this link for more information about file path.

How to Place a Field Vertically and Horizontally center in the Blackberry Screen

For placing a Field (for example HorizontalFieldManager) in center of the screen simple setting margin will do the trick.

Here is an example of placing a HorizontalFieldManager in the center.



HorizontalFieldManager hfm = new HorizontalFieldManager();

LabelField testLabel1 = new LabelField( "Test Label1");
LabelField testLabel2 = new LabelField( "Test Label2");
hfm.add(testLabel1);
hfm.add(testLabel2);

int leftEmptySpace = (Display.getWidth() - hfm.getPreferredWidth()) / 2;
int topEmptySpace = (Display.getHeight() - hfm.getPreferredHeight()) / 2;
hfm.setMargin(topEmptySpace, 0, 0, leftEmptySpace);

//now add this manager to MainScreen
this.add(hfm);





How to set Background color of Blackberry Screen

For setting background color in Blackberry screen we need to do the following.

Disable Vertical scrolling of the main screen.

Now create a VerticalFieldManager with vertical scroll enabled. This will be the main manger where screen component have to add. Set the width and height of this manager as Screen width and height by overriding sublayout() method.
And override paint() method to set backgroung color

Here is the example code with above implemented.



import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;

class TestScreen extends MainScreen{

private VerticalFieldManager verticalManager;
private HorizontalFieldManager hrzManager;

TestScreen()
{
super(NO_VERTICAL_SCROLL);

//rather than adding component
//in the mainScreen add components
//in this verticalManager and then
//add this manager to mainScreen
verticalManager = new VerticalFieldManager(
Manager.VERTICAL_SCROLL |
Manager.VERTICAL_SCROLLBAR)
{
public void paint(Graphics graphics)
{
//blue
graphics.setBackgroundColor(0x000000ff);
graphics.clear();
super.paint(graphics);
}
protected void sublayout( int maxWidth, int maxHeight )
{
int width = Display.getWidth();
int height = Display.getHeight();
super.sublayout( width, height);
setExtent( width, height);
}
};

ButtonField button1 = new ButtonField("Button1");
ButtonField button2 = new ButtonField("Button2");
ButtonField button3 = new ButtonField("Button3");
ButtonField button4 = new ButtonField("Button4");
ButtonField button5 = new ButtonField("Button5");

verticalManager.add(button1);
verticalManager.add(button2);
verticalManager.add(button3);
verticalManager.add(button4);
verticalManager.add(button5);
this.add(verticalManager);

}
}



Also have a look at this KnowledgeBase Article for getting better idea.


How to set Background Image in Blackberry

For setting image in the background of the Blackberry screen we need to do the following.

First create a VerticalFieldManager and override the paint method of that manager and then draw Bitmap inside paint() method with the device width and height. Disable vertical scrolling of this manager.

Now create another VerticalFieldManager with vertical scroll enabled. This will be the main manger where screen component have to add. Set the width and height of this manager as Screen width and height by overriding sublayout() method.


Here is the example code with above implemented.


import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;

public class TestScreen extends MainScreen
{

private VerticalFieldManager mainManager;
private VerticalFieldManager subManager;
private Bitmap _backgroundBitmap = Bitmap.getBitmapResource
("sunset.png");
private int deviceWidth = Display.getWidth();
private int deviceHeight = Display.getHeight();

public TestScreen()
{
super(NO_VERTICAL_SCROLL);

//this manager is used for the static background image
mainManager = new VerticalFieldManager(
Manager.NO_VERTICAL_SCROLL |
Manager.NO_VERTICAL_SCROLLBAR )
{
public void paint(Graphics graphics)
{
graphics.clear();
graphics.drawBitmap(0, 0, deviceWidth,
deviceHeight, _backgroundBitmap, 0, 0);
super.paint(graphics);
}
};

//this manger is used for adding the componentes
subManager = new VerticalFieldManager(
Manager.VERTICAL_SCROLL |
Manager.VERTICAL_SCROLLBAR )
{
protected void sublayout(int maxWidth, int maxHeight)
{
int displayWidth = deviceWidth;
int displayHeight = deviceHeight;

super.sublayout( displayWidth, displayHeight);
setExtent( displayWidth, displayHeight);
}
};

/// add your component to this subManager
subManager.add(new ButtonField("Test Button"));
/////////////////////////////////////////

//add subManager over the mainManager
mainManager.add(subManager);

//finally add the mainManager over the screen
this.add(mainManager);
}
}



Wednesday, July 22, 2009

HelloWorld in BlackBerry

Before starting anything its became a tradition to start with HelloWorld.
Here list of HelloWorld programming in 200 different languages.

So to maintain the tradition we are going to write helloWorld in BlackBerry. :)

1. Open the JDE

2. Create a new workspace (File -> New -> Workspaces) and name it as helloWorld .

3. Create a new Project under the helloWorld workspace
File -> New -> Projects or
Right click on the helloWorld.jdw (on the left side of the JDE) and click 'Create new Project in
helloWorld.jdw ...' and name it as helloWorld.

4. Now create a file under the helloWorld project.
Right click on the helloWorld.jdp and click 'Create new File in
Project ...' and name it as HelloWorld.java

5. Paste the following in the HelloWorld.java file.




import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.system.*;

class HelloWorld extends UiApplication
{
public HelloWorld()
{
super();

/// creating mainScreen to diaply hellowrld
MainScreen helloWorldScreen = new MainScreen();
LabelField lbl = new LabelField("Hello World");
helloWorldScreen.add(lbl);

//pushing that screen to Display
this.pushScreen(helloWorldScreen);
}

public static void main(String[] args)
{
HelloWorld helloWorld = new HelloWorld();
helloWorld.enterEventDispatcher();
}
}


6. Now build and Run the project (Build -> Build All and Run)

7. Go to the home screen of the simulator and click the application named helloWorld.

8. Enjoy HelloWorld in the BB Simulator.

Create the Environment for BlackBerry development

Before starting HelloWorld we need to create the environment for BlackBerry development.

Blackberry applications can be developed using Blackberry JDE, Eclipse Plugin, Netbeans plugin and Visual Studio Plugin.

I use Blackberry JDE for my development. I prefer this because this is provided by the RIM.


We have to follow the following steps for making our PC to start HelloWorld using BB JDE.

1. Before staring it is very important to choose the JDE. Have a look at this KnowledgeBase article.

2. For example you chosen JDE 4.6.0.
You can download any other version from here.

3. Now Install the "BlackBerry_JDE_4.6.0.exe" that you downloaded

4. Install any latest JDK (ex: jdk-6u5-windows-i586-p.exe)

5. Update your environment variable.
Control Panel -> System -> Environment variables -> click path in the system variables ->
Edit. Now add the following in Variable value ; each with a semicolon in the end
a) C:\Program Files\Java\jdk1.6.0_05\bin

b) C:\Program Files\Java\jre1.6.0_05\bin

c) C:\Program Files\Research In Motion\BlackBerry JDE 4.6.0\bin

6. Restart your PC or simply the logoff will do.

Now we are ready to start HelloWorld in Blackberry :)