I want to trap events on two custom Fields which I had created by extending the Field class.
The events should only be touch events.
One field uses graphics.drawRect(10,10,20,20) and other field uses graphics.drawRect(50,50,20,20).
(I will not use hardcoded values, but am writing them here just for an example).
I should be able to trap the events individually; that means different events on different fields.
My code looks like:
Main screen Class:
package mypackage;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.container.MainScreen;
public final class MyScreen extends MainScreen
{
CustomFieldManager cfm;
public MyScreen()
{
cfm=new CustomFieldManager();
CustomButtonField cb=new CustomButtonField(Field.FOCUSABLE,20,20,40,40);
CustomButtonField cb1=new CustomButtonField(Field.FOCUSABLE,70,70,40,40);
new CustomButtonField(cb,cb1);
cfm.add(cb);
cfm.add(cb1);
add(cfm);
}
}
Field class:
package mypackage;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.Dialog;
public class CustomButtonField extends Field {
int a,b,c,d;
CustomButtonField c1,c2;
public CustomButtonField(long style,int a,int b,int c,int d){
super(style);
this.a=a;
this.b=b;
this.c=c;
this.d=d;
}
public CustomButtonField(Object o1,Object o2){
c1=(CustomButtonField)o1;
c2=(CustomButtonField)o2;
}
public void movefirst(){
Dialog.alert("god");
}
protected void drawFocus(Graphics graphics, boolean on) {
}
protected void layout(int width, int height) {
setExtent(200, 200);
}
protected void paint(Graphics graphics) {
graphics.drawRect(a, b, c, d);
}
protected boolean navigationClick(int status, int time) {
fieldChangeNotify(0);
return true;
}
}
and manager class :
package mypackage;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.component.Dialog;
public class CustomFieldManager extends Manager {
CustomButtonField first, second;
public CustomFieldManager() {
super(Manager.NO_HORIZONTAL_SCROLL | Manager.NO_VERTICAL_SCROLL);
}
protected void sublayout(int arg0, int arg1) {
int numberOfFields = getFieldCount();
for (int i = 0; i < numberOfFields; i++) {
// Get the field.
first = (CustomButtonField) getField(i);
setPositionChild(first, 0, 0);
layoutChild(first, 110, 110);
}
setExtent(200, 200);
}
setPositionChild(first, 50, 50);
invalidate();
}
}
If I understood you right, you just need to override this method:
protected boolean touchEvent(TouchEvent message)
in both custom field classes. And implement the functionality you want.
I think we need some clarification.
A Field in BlackBerry Java is given an 'extent' - basically a rectangle - and it paints into this area. When displayed on the screen, all 'events' in this Field's extent should be directed to that Field automatically by the framework. As far as the Field is concerned, the extent always starts at 0,0, and extends as many pixels as the Field has. In fact it is this extent that defines the size of the Field.
Now within paint, you can paint what you like for the each Field (as long as you stay inside its extent). So if you have a Field with an extent that was say 100 x 100 pixels, then you paint the left hand side of your Field red and the right hand side blue, by doing something like this:
graphics.setColor(Color.Red);
graphics.drawRect(0,0,50,100);
graphics.setColor(Color.Blue);
graohics.drawRect(50,0,100,100);
Now if you did this, you might want separately detectable areas - say the red and the blue areas. And while this is possible and you can detect it using touchEvent(), you would find it a lot easier to actually display two Fields, one all red and one all blue. Separate Fields make it a lot easier to use the standard BB methods, and in addition, also make it possible to use the trackpad to scroll round the different Fields. Remember you can't use touchevent() on non touch phones.
Anyway, with this additional information, can you please clarify your question. Do you have one Field with different areas? If you have two different Fields, remember that you are painting within each Field's extent.
Related
i am new to blackberry development and want to add an image to a sample blackberry application. I have tried multiple tutorials, but the image is not displaying in the background
can any one kindly tell me what is the problem?
/**
* This class extends the UiApplication class, providing a graphical user
* interface.
*/
public class Diverse extends UiApplication {
private Bitmap backgroundBitmap;
private Bitmap fieldBitmap;
public static void main(String[] args) {
Diverse diverse = new Diverse();
diverse.enterEventDispatcher();
}
/**
* Creates a new MyApp object
*/
public Diverse() {
//The background image.
backgroundBitmap = Bitmap.getBitmapResource("background.png");
MainScreen mainScreen = new MainScreen();
HorizontalFieldManager horizontalFieldManager = new HorizontalFieldManager(HorizontalFieldManager.USE_ALL_WIDTH | HorizontalFieldManager.USE_ALL_HEIGHT){
//Override the paint method to draw the background image.
public void paint(Graphics graphics)
{
//Draw the background image and then call paint.
graphics.drawBitmap(0, 0, 240, 240, backgroundBitmap, 0, 0);
super.paint(graphics);
}
};
//The LabelField will show up through the transparent image.
LabelField labelField = new LabelField("This is a label");
//A bitmap field with a transparent image.
//The background image will show up through the transparent BitMapField image.
BitmapField bitmapField = new BitmapField(Bitmap.getBitmapResource("field.png"));
//Add the manager to the screen.
mainScreen.add(horizontalFieldManager);
//Add the fields to the manager.
horizontalFieldManager.add(labelField);
horizontalFieldManager.add(bitmapField);
// Push a screen onto the UI stack for rendering.
pushScreen(new DiverseScreen());
}
}
and DiverseScreen class is
package diverse;
import net.rim.device.api.ui.container.MainScreen;
/**
* A class extending the MainScreen class, which provides default standard
* behavior for BlackBerry GUI applications.
*/
public final class DiverseScreen extends MainScreen
{
/**
* Creates a new MyScreen object
*/
public DiverseScreen()
{
// Set the displayed title of the screen
setTitle("Diverse");
}
}
The problem is that you have set the background image for one screen, but you never displayed that screen. Then, you displayed a different screen that did not have a background image set.
First, it helps to understand the BlackBerry UI framework. It allows you to create a hierarchy of objects on screen. At the top level, you have a Screen (or subclass of Screen), and then inside of the Screen, you have Managers, and inside them are Fields. But, each level must be added to a container of some kind, and finally, the top-level Screen must be displayed with something like pushScreen().
See a little more description on this hierarchy in a recent answer here
In your situation, you should change this line
MainScreen mainScreen = new MainScreen();
to
DiverseScreen mainScreen = new DiverseScreen();
and then change this line
pushScreen(new DiverseScreen());
to
pushScreen(mainScreen);
since mainScreen is the instance where you added a horizontal field manager that draws your background image.
Hi i have implemented scrolling text horizontally through this link LabelField Marquee. But i have one problem,the text is scrolling quite good but its been over-written on the original text which was added.Can anyone have any idea how to cope from this problem? I also tried to refresh the view by invalidate() but of no use. i have added the screenshot of the problem which i am facing.
Any help would be appreciable.
Thank you.
I would suggest you to change paint method to next:
public void paint(Graphics graphics) {
currentText = this.getText();
if (currentChar < currentText.length()) {
currentText = currentText.substring(currentChar);
}
graphics.drawText(currentText, 0, 0, DrawStyle.ELLIPSIS, 200);
}
So don't call super.paint() in your paint.
I've rewritten (in a more simple way) the answer you linked. It works fine.
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.DrawStyle;
import java.util.Timer;
import java.util.TimerTask;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.MainScreen;
public class MyScreen extends MainScreen {
public MyScreen() {
super();
MarqueeLabel testLabel2 = new MarqueeLabel("This is a long long " +
"long long long long long long long long long long long " +
"long long marquee", Field.FOCUSABLE);
add(testLabel2);
}
class MarqueeLabel extends LabelField {
// Here MarqueeLabel code from your SO linked example
}
}
I'm developing an application in BlackBerry and I have many HorizontalFieldManagers filled with components like shown in the image below:
And I have to add many HorizontalFieldManagers like these within a for loop which are dynamically populated. When taken together, it looks like a single row in a list. So far, I have been able to do this.
But the problem is, the user should be able to click a "row" like this. But as the HorizontalFieldManager is not focusable or clickable, and because it has 4 components inside it and all 4 are equally important, I have not been able to figure-out a way to do this.
So can anyone please suggest a way to do what I'm trying? Basically, the user should be able to click a "row" which is shown in the image. This "row" is made up of many components (2 HorizontalFieldManagers, 1 VerticalFieldManager, 1 BitmapField and 3 LabelFields).
Any help greatly appreciated!
BBdev directly answered your question, but as you noticed, the performance is quite slow. This is because using a manager to stamp out hundreds of rows like this adds a lot of overhead to the layout step of the UI. Layout will run against all of those managers, every time something changes on the screen - including each time you add a new row. This is fundamentally quadratic.
The way to speed this up is to use a ListField instead. The one pain point of a ListField is that you have to do the drawing directly, instead of relying on the standard OS fields. But the advantage is that the ListField performs very quickly - each row has a fixed height, so the ListField can quickly determine which rows are visible, and then call the paint code just for those rows.
This means the work scales with the visible size of the field, instead of the virtual size of the field. This is a very desirable property to maintain when writing UI code, as the virtual depth of a UI has no bounds, but the physical screen has a fixed number of pixels, so by scaling the work with the visible portion of the UI, you maintain good performance.
The below code will make your HorizontalFieldManager clickable, And add your component in this Hfm as you want.
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.TouchEvent;
import net.rim.device.api.ui.Touchscreen;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.NullField;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.MainScreen;
public class sample extends MainScreen implements FieldChangeListener{
HorizontalFieldManager logInDetailManager=null;
int background_color=0;
public sample() {
logInDetailManager = new HorizontalFieldManager(Manager.USE_ALL_WIDTH|Field.FOCUSABLE){
protected void sublayout(int maxWidth, int maxHeight) {
int height=40;
super.sublayout(Display.getWidth(), height);
setExtent(Display.getWidth(), height);
}
protected void paint(Graphics graphics) {
graphics.setBackgroundColor(background_color);
graphics.clear();
invalidate();
super.paint(graphics);
}
protected void onFocus(int direction) {
super.onFocus(direction);
background_color=Color.RED;
invalidate();
}
protected void onUnfocus() {
invalidate();
background_color=Color.GREEN;
}
protected boolean navigationClick(int status, int time) {
if(Touchscreen.isSupported()){
return false;
}else{
fieldChangeNotify(1);
return true;
}
}
protected boolean touchEvent(TouchEvent message)
{
if (TouchEvent.CLICK == message.getEvent())
{
FieldChangeListener listener = getChangeListener();
if (null != listener)
this.setFocus();
listener.fieldChanged(this, 1);
}
return super.touchEvent(message);
}
};
logInDetailManager.setChangeListener(this);
logInDetailManager.add(new LabelField("hello"));
logInDetailManager.add(new NullField(Field.FOCUSABLE));
add(logInDetailManager);
add(new LabelField("good",Field.FOCUSABLE));
}
public void fieldChanged(Field field, int context) {
if(field==logInDetailManager){
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.inform("Hi how are you?");
}
});
}
}
}
Hope this will help you . Cheers :)
How to handle the focus color when you have an array of horizontal fields instead?
for (int i = 0; i < listSize; i++) {
logInDetailManager[i] = new HorizontalFieldManager(
Manager.USE_ALL_WIDTH | Field.FOCUSABLE) {
Since one item of the array is always focused the whole list is all red.
The below class extends labelfield but when I display a large amount text it does'nt wrap to a new line. The text just trails across the screen. When I use LabelField the text wraps. Do I need to update the paint method?
Thanks
import net.rim.device.api.ui.DrawStyle;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.LabelField;
public class FCLabelField extends LabelField {
private Object text;
private Font font;
private int colour;
private long style;
public FCLabelField(Object text, long style , Font font, int colour) {
super(text, style);
this.text = text;
this.font = font;
this.colour = colour;
}
protected void paint(Graphics graphics) {
graphics.setColor(colour);
graphics.setFont(font);
graphics.drawText(text.toString(), 0, 0, DrawStyle.HCENTER, getContentWidth());
}
}
This works -
import net.rim.device.api.ui.DrawStyle;
import net.rim.device.api.ui.Font;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.component.LabelField;
public class FCLabelField extends LabelField {
private Object text;
private Font font;
private int colour;
private long style;
public FCLabelField(Object text, long style , Font font, int colour) {
super(text, style);
this.text = text;
this.colour = colour;
super.setFont(font);
}
protected void paint(Graphics graphics) {
graphics.setColor(this.colour);
super.paint(graphics);
}
}
In your first version you are overriding the paint method and not calling the superclass' paint method. In the second, you are, this allows the code in the base class to paint the text.
If you don't want to call the superclass' paint method, you have to change your paint method to calculate the extent of the string you're going to draw and to split it at the appropriate points, making multiple calls to drawText to draw each fragment separately at a different y location. That's what the paint method in LabelField does by default, so you need to emulate it.
When you do call the superclass paint method, the reason setting the font on the superclass works and setting the font in your paint method doesn't is because the superclass' paint method is calling setFont on the Graphics object, overwriting what you just did in your paint method.
Can you please tell me how to customize my components at a BlackBerry?
E.g. I need a verticalfieldManager which will have a label field, an image, placed one after the other. Also this verticalFieldManager should be in the center of the screen, it should not start from the immediate left or right of the screen.
I want a border for this verticalFieldManager, too.
It should be noted that the BorderFactory class wasn't added until JDE 4.6.0. If you are your application on a older JDE platform then you will have to override the vertical manager's paint method to draw the border.
-Glen
No need to customized the class. Hope, following code will solve your problem.
public class Sample extends UiApplication {
public Sample() {
pushScreen(new SampleScreen());
}
public static void main(String[] args) {
Sample sample = new Sample();
sample.enterEventDispatcher();
}
private static class SampleScreen extends MainScreen {
public SampleScreen() {
VerticalFieldManager vfManager = new VerticalFieldManager(Field.FIELD_HCENTER);
vfManager.add(new LabelField("Test Label"));
vfManager.add(new BitmapField(Bitmap.getBitmapResource("image.png")));
vfManager.setBorder(BorderFactory.createRoundedBorder(
new XYEdges(5, 5, 5, 5),
Color.ORANGE,
Border.STYLE_SOLID
));
add(vfManager);
}
}
}
You can also create custom manager and set the position of contents as per your choice and requirement
now add your custom manager to a manager say basemanager and add this basemanager to screen