Welcome!

Welcome to the Official BlackBerry Support Community Forums. This is your resource to discuss support topics with your peers, and learn from each other. New to the forum? Please visit the ‘Getting Started’ link below.
inside custom component

Java Development

Reply
Developer
indusBULL
Posts: 207
Registered: ‎09-10-2010

BitmapButtonField with focus border

Hi everyone

 

  I am trying to implement a custom button with background image. The button should have different border color for focus (RED) & unFocus(WHITE). I am able to change the border color to blue on focus but it doesn't change back to white on unFocus. I think that unFoucs method is not invoked. But I dont know why it is not invoked. I have included the code below. I will really appreciate if someone can help me with this.

 

Thank you.

 

 

public class BitmapBorderBtnField extends BitmapField {

        private Bitmap _bitmap;
        private int myBorderColor;
        
        /**
         * The Constructor.
         *       
         * @param bitmap the bitmap
         */
        public BitmapBorderBtnField(Bitmap bitmap) {
                super(bitmap, BitmapField.FOCUSABLE);         
                this._bitmap = bitmap;
                myBorderColor = Color.WHITE;
        }

        /**
         * The Constructor.
         *
         * @param l the style
         * @param bitmap the bitmap
         */
        public BitmapBorderBtnField(long l, Bitmap bitmap) {
                super(bitmap, l | BitmapField.FOCUSABLE );                
                this._bitmap = bitmap;
                myBorderColor = Color.WHITE;
        }

                         
        protected void onFocus(int direction){
        	myBorderColor = Color.RED;
        	invalidate();
//        	super.onFocus(direction);
        }
        
        protected void onUnFocus(){
        	myBorderColor = Color.WHITE;
        	invalidate();
        //	super.onUnfocus();
        }

        protected void drawFocus(Graphics graphics, boolean b) {
        }

        public int getPreferredWidth() {
            return _bitmap.getWidth();
        }
        
        public int getPreferredHeight() {
            return _bitmap.getHeight();
        }
        
        
        protected void layout(int i, int i1) {
                super.layout(_bitmap.getWidth(), _bitmap.getHeight() );
                setExtent(_bitmap.getWidth(), _bitmap.getHeight() );
        }

        
        protected void paint( Graphics g ) {    	
        	g.setColor(myBorderColor);
        	g.drawRoundRect(0, 0, getPreferredWidth(), getPreferredHeight(), 12, 12);
       //	g.setColor(prevColor);
        	g.drawBitmap( 0, 0, _bitmap.getWidth(), _bitmap.getHeight(), _bitmap, 0, 0 );
        }
        
        public void setBtnPosition(int x, int y){
        	setPosition(x, y);
        }
        
        protected void fieldChangeNotify(int i) {            
        	super.fieldChangeNotify(i);              
        }

        protected boolean keyDown(int i, int i1) {
                if (Keypad.key(i) == Keypad.KEY_ENTER && (KeypadListener.STATUS_ALT & Keypad.status(i)) == 0) {
                        this.getChangeListener().fieldChanged(this, 0);
                }
                return super.keyDown(i, i1);
        }

        protected boolean navigationClick(int i, int i1) {
                fieldChangeNotify(1);
                return true;
        }

}

 

 

Please use plain text.
Developer
arkadyz
Posts: 2,268
Registered: ‎07-08-2009
My Carrier: various

Re: BitmapButtonField with focus border

Indeed, onUnfocus is flawed and is not always called. The safest approach which, in my experience, works every time is to use FocusChangeListener. Make your BitmapBorderBtnField not only extend BitmapField but also implement FocusChangeListener, include a public void focusChanged(Field field, int reason) method, check the reason parameter and react appropriately to FOCUS_GAINED and FOCUS_LOST. In your constructors, invoke setFocusListener(this) somewhere.

 

Some general suggestions:

1. Replace the first constructor with

        public BitmapBorderBtnField(Bitmap bitmap) {
                this(0L, bitmap);
        }

2. Remove setExtent from your layout - super.layout already does that. Frankly, I think you don't need that layout override at all - the built-in one will do a better and more efficient job at that.

3. setBtnPosition will throw an exception if called at the wrong time - think twice whether you need it at all. It can be called during the manager's sublayout only where it can be safely substituted with setPositionChild(...).

4. fieldChangeNotify override is superfluous. Remove it.

5. keyDown will throw a NullPointerException if you don't setChangeListener on this field. Change it to something like that:

        protected boolean keyDown(int i, int i1) {
                if (Keypad.key(i) == Keypad.KEY_ENTER && (KeypadListener.STATUS_ALT & Keypad.status(i)) == 0) {
                        fieldChangeNotify(0);
                }
                return super.keyDown(i, i1);
        }

fieldChangeNotify knows to check the field change listener by itself.  Also consider passing it FieldChangeListener.PROGRAMMATIC rather than 0 - this way the field won't be marked dirty.

6. Override navigationUnclick rather than navigationClick - this will prevent the default menu from popping up.

----------------------------------------------------------
please click 'Accept Solution' on posts that provide the solution to the question you've posted. Don't say "Thanks", press 'Like' button instead!
Please use plain text.
Developer
indusBULL
Posts: 207
Registered: ‎09-10-2010

Re: BitmapButtonField with focus border

[ Edited ]

@ arkadyz

 

thank you very much for your response. I really appreciate for pointing out details. I have made the changes as you have suggested.

 

Before I was trying to draw focus border in paint method. But this time, I am using setBorder with ViSUAL_STATE_FOCUS. It works as expected. It shows the border on focus. The only problem is that when I tried to increase the thickness of the border, the bitmap moves little towards right bottom on focus. It is not centered.  How do I stop movement of bitmap?

 

And between two methods of setting focus border (paint() & setBorder() ), which one is better? (JDE 5.0)

 

 

public class BitmapBorderBtnField extends BitmapField {

        private Bitmap _bitmap;
        Border focusBorder = BorderFactory.createRoundedBorder(new XYEdges(2,2,2,2), Color.RED, Border.STYLE_SOLID);

        public BitmapBorderBtnField(Bitmap bitmap) {
 this(BitmapField.FOCUSABLE,bitmap); } public BitmapBorderBtnField(long l, Bitmap bitmap) { super(bitmap, l | BitmapField.FOCUSABLE); this._bitmap = bitmap; this.setBorder(Field.VISUAL_STATE_FOCUS, focusBorder); // myBorderColor = Color.WHITE; // setFocusListener(this); } public int getPreferredHeight() { return _bitmap.getHeight(); } protected void layout(int i, int i1) { super.layout(_bitmap.getWidth(), _bitmap.getHeight() ); } protected boolean keyDown(int i, int i1) { if (Keypad.key(i) == Keypad.KEY_ENTER && (KeypadListener.STATUS_ALT & Keypad.status(i)) == 0) { fieldChangeNotify(FieldChangeListener.PROGRAMMATIC); } return super.keyDown(i, i1); } protected boolean navigationClick(int i, int i1) { fieldChangeNotify(1); return true; } protected void drawFocus(Graphics graphics, boolean b) { //Do Nothing } }

 

on your this suggestion

 

2. Remove setExtent from your layout - super.layout already does that. Frankly, I think you don't need that layout override at all - the built-in one will do a better and more efficient job at that.

 

when I remove the layout method, it doesn't layout bitmap field.

 

Thank you.

 

Please use plain text.
Developer
arkadyz
Posts: 2,268
Registered: ‎07-08-2009
My Carrier: various

Re: BitmapButtonField with focus border

 


indusBULL wrote:

2. Remove setExtent from your layout - super.layout already does that. Frankly, I think you don't need that layout override at all - the built-in one will do a better and more efficient job at that.

 

when I remove the layout method, it doesn't layout bitmap field.

 

Thank you.

 


 

I think it's something else that doesn't lay out the field - BitmapField is perfectly capable of laying itself out.  Anyway, your field is not centered because you forget to add the border to the bitmap dimensions, thus cutting the image on the right and bottom.

 

So:

1. Try to find out what prevents the built-in layout from doing its job.

2. If you cannot figure it out, at least add border dimensions to your super.layout call.

----------------------------------------------------------
please click 'Accept Solution' on posts that provide the solution to the question you've posted. Don't say "Thanks", press 'Like' button instead!
Please use plain text.
Contributor
jlbenc
Posts: 28
Registered: ‎05-02-2010
My Carrier: Claro Dominican Republic

Re: BitmapButtonField with focus border

If it helps anyone, here's my ActiveBitmapField (basically a hilghtable, clickable, ENTER-key-aware bitmap), using the 4.5 API:

 

 

import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.FieldChangeListener;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.XYRect;
import net.rim.device.api.ui.component.BitmapField;

public class ActiveBitmapField extends BitmapField {
	
	int highLightThickness = 2;
	int focusColor = Color.BLUE;
	
	public int getHighLightThickness() {
		return highLightThickness;
	}

	public void setHighLightThickness(int highLightThickness) {
		this.highLightThickness = highLightThickness;
	}

	public int getFocusColor() {
		return focusColor;
	}

	public void setFocusColor(int focusColor) {
		this.focusColor = focusColor;
	}

	ActiveBitmapField( Bitmap bmp, long style  ){
		super( bmp, style);
	}
	
	ActiveBitmapField( Bitmap bmp, long style, int highLightThickness  ){
		this( bmp, style);
		this.highLightThickness = highLightThickness; 
	}
	
	
	protected void drawFocus(Graphics g, boolean on) {
			if (on) {
				XYRect ex = this.getExtent();
				g.setColor( focusColor );
				for (int i=0; i <= highLightThickness; i++){ 
					g.drawRect(ex.x+i, ex.y+i, ex.width-i*2, ex.height-i*2);
				}
			}
		}
		protected boolean navigationClick(int status, int time) {
				// PROGRAMMATIC prevents from setting the field to DIRTY,
			    // (thus not prompting to save the screen on exit):
		        fieldChangeNotify(FieldChangeListener.PROGRAMMATIC);
		        return true;
		}
	    protected boolean keyChar(char key, int status, int time) {
	        if (key == Keypad.KEY_ENTER) {
				// PROGRAMMATIC prevents from setting the field to DIRTY,
			    // (thus not prompting to save the screen on exit):
	            fieldChangeNotify(FieldChangeListener.PROGRAMMATIC);
	            return true;
	        }
	        return super.keyChar(key, status, time);   
	    }
}

 

 

 

 

Please use plain text.
Developer
dmazgalin
Posts: 92
Registered: ‎01-15-2009

Re: BitmapButtonField with focus border

Hi. Try to center your bitmap in this line

g.drawBitmap( 0, 0, _bitmap.getWidth(), _bitmap.getHeight(), _bitmap, 0, 0 );

Calculate


   otstupX = (getFieldWidth() - _bitmap.getWidth()) / 2;
   otstupY = (getFieldHeight() - _bitmap.getHeight()) / 2;

and than

g.drawBitmap(otstupX, otstupY, _bitmap.getWidth(), _bitmap.getHeight(), _bitmap, 0, 0);

 

Regards, Dmitry.

Please use plain text.
Developer
indusBULL
Posts: 207
Registered: ‎09-10-2010

Re: BitmapButtonField with focus border

Sorry for replying too late.

 

@arkadyz

 

You are right. I tried the same code in different manager and it worked perfectly fine without layout method. I still need to figure out why it didn't work with previous manager. Thank you.

 

@jlbenc

 

Thank you very much posting your code. It is exactly what I was looking for but much easier implementation.

 

 

@dmazgalin

 

 


otstupX = (getFieldWidth() - _bitmap.getWidth()) / 2;
   otstupY = (getFieldHeight() - _bitmap.getHeight()) / 2;

and than

g.drawBitmap(otstupX, otstupY, _bitmap.getWidth(), _bitmap.getHeight(), _bitmap, 0, 0);

 

 


 

 

Thanks for reply. I tried out your suggestion. But it didn't solve my problem. When you say getFieldWidth, do you mean getWidth() method of field?

 


Please use plain text.
Trusted Contributor
avi_yach
Posts: 184
Registered: ‎11-26-2010

Re: BitmapButtonField with focus border

 _bitmapField = new BitmapField(bitmap,BitmapField.FOCUSABLE|BitmapField.FIELD_HCENTER){
            	 /*protected void layout(int width, int height) {
                     setExtent(bitmap.getWidth()+3, bitmap.getHeight()+3);
                 }*/
            	Border bF = BorderFactory.createRoundedBorder(new XYEdges(1,1,1,1),Color.AQUA,Border.STYLE_FILLED);
            	Border bUF = BorderFactory.createRoundedBorder(new XYEdges(1,1,1,1), 0x818181,Border.STYLE_FILLED);
            	protected void onFocus(int direction) {
            		this.setBorder(bF);
    			}
    			protected void onUnfocus() {
    				this.setBorder(bUF);
    			} 
            };		       

 Hello all, I am using the above solution, posted the trick just in case it might help someone, I request the author to mark this thread as closed and thanks to all the abpve contributors, this post has helped me cross the hurlde.

 

A Y

Please use plain text.