1

I have a ImageButton in a VerticalFieldManager and VFM in a HorizontalFieldManager. The ImageButton click event is firing when I click anywhere in the surrounding field. I want that click event to only fire when clicking the ImageButton, not the field (VFM or HFM).

Following is the code:

ImageButton Login = new ImageButton(configModel.getLoginButton(), FOCUSABLE|Field.FIELD_RIGHT, "login.png", "plogin.png",0x9cbe95);
HorizontalFieldManager hfm = new HorizontalFieldManager(USE_ALL_WIDTH);
VerticalFieldManager loginButtonVfm = new VerticalFieldManager(USE_ALL_WIDTH);

loginButtonVfm.add(Login);
hfm.add(loginButtonVfm);
add(hfm);


FieldChangeListener loginListener = new FieldChangeListener() { 
public void fieldChanged(Field field, int context) {
     Dialog.alert("Fired");
    }
}
Login.setChangeListener(loginListener); 

ImageButton Class Code is here:

public class ImageButton extends Field{

        //Image Button Class 
        private String _label;
        private int _labelHeight;
        private int _labelWidth;
        private Font _font;

        private Bitmap _currentPicture;
        private Bitmap _onPicture;
        private Bitmap _offPicture;
        int color;

        public ImageButton(String text, long style ,String img, String img_hvr, int color){
            super(style);

            _offPicture = Bitmap.getBitmapResource(img);
            _onPicture = Bitmap.getBitmapResource(img_hvr);

            _font = Font.getDefault().derive(Font.BOLD, 7, Ui.UNITS_pt);
            _label = text;


            _labelHeight = _onPicture.getHeight();  
            _labelWidth = _onPicture.getWidth();

            this.color = color;

            _currentPicture = _offPicture;
        }
        public void setImage(String img){

            _offPicture = Bitmap.getBitmapResource(img); 
            _currentPicture = _offPicture;
        }

        /**
         * @return The text on the button
         */
        public void setText(String text){
            _label = text;
        }
            String getText(){
            return _label;
        }

        /**
         * Field implementation.
         * @see net.rim.device.api.ui.Field#getPreferredHeight()
         */
        public int getPreferredHeight(){
            return _labelHeight;
        }
        /**
         * Field implementation.
         * @see net.rim.device.api.ui.Field#getPreferredWidth()
         */
        public int getPreferredWidth(){
            return _labelWidth;
        }

        /**
         * Field implementation.  Changes the picture when focus is gained.
         * @see net.rim.device.api.ui.Field#onFocus(int)
         */
        protected void onFocus(int direction) {

             _currentPicture = _onPicture;
          //  invalidate();
            super.onFocus(direction);
        }

        /**
         * Field implementation.  Changes picture back when focus is lost.
         * @see net.rim.device.api.ui.Field#onUnfocus()
         */
        protected void onUnfocus() {
            _currentPicture = _offPicture;
            invalidate();
            super.onUnfocus();
        }

        /**
         * Field implementation.  
         * @see net.rim.device.api.ui.Field#drawFocus(Graphics, boolean)
         */
//      protected void drawFocus(Graphics graphics, boolean on) {
//          // Do nothing
//      }
        protected void drawFocus(Graphics graphics, boolean on) {
            if (on) {
                     //draw your own custom focus.
                    }
                }
        /**
         * Field implementation.
         * @see net.rim.device.api.ui.Field#layout(int, int)
         */
        protected void layout(int width, int height) {
            setExtent(Math.min( width, getPreferredWidth()),
            Math.min( height, getPreferredHeight()));
        }
        /**
         * Field implementation.
         * @see net.rim.device.api.ui.Field#paint(Graphics)
         */
        protected void paint(Graphics graphics){      
            // First draw the background colour and picture
            graphics.setColor(this.color);
            graphics.fillRect(0, 0, getWidth(), getHeight());
            graphics.drawBitmap(0, 0, getWidth(), getHeight(), _currentPicture, 0, 0);

            // Then draw the text
            graphics.setColor(Color.WHITE);
            graphics.setFont(_font);
            graphics.setFont(graphics.getFont().derive(Font.BOLD)); 
            graphics.drawText(_label, 5,9,
                (int)( getStyle() & DrawStyle.ELLIPSIS | DrawStyle.VALIGN_MASK | DrawStyle.HALIGN_MASK),
                getWidth() - 6 );

        }

        /**
         * Overridden so that the Event Dispatch thread can catch this event
         * instead of having it be caught here..
         * @see net.rim.device.api.ui.Field#navigationClick(int, int)
         */
        protected boolean navigationClick(int status, int time){
            fieldChangeNotify(1);
            return true;
        } 
}
4

1 回答 1

1

This kind of thing is actually pretty easy to find bugs in, when you try to write custom fields yourself. (It's not your fault ... BlackBerry Java makes this stuff more difficult than it really should be!)

I think the easiest way to solve this problem is to reuse something that someone else has already tested. I would recommend looking at the BlackBerry Advanced UI library, in particular, these two classes:

BaseButtonField

BitmapButtonField

As I think they do exactly what you need. I believe the important code you need to change, or add to your ImageButton class is this:

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

protected boolean navigationClick( int status, int time ) 
{
    if (status != 0) clickButton(); 
    return true;    
}

protected boolean trackwheelClick( int status, int time )
{        
    if (status != 0) clickButton();    
    return true;
}

protected boolean invokeAction( int action ) 
{
    switch( action ) {
        case ACTION_INVOKE: {
            clickButton(); 
            return true;
        }
    }
    return super.invokeAction( action );
}    

protected boolean touchEvent( TouchEvent message )
{
    int x = message.getX( 1 );
    int y = message.getY( 1 );
    if( x < 0 || y < 0 || x > getExtent().width || y > getExtent().height ) {
        // Outside the field
        return false;
    }
    switch( message.getEvent() ) {

        case TouchEvent.UNCLICK:
            clickButton();
            return true;
    }
    return super.touchEvent( message );
}

/**
 * A public way to click this button
 */
public void clickButton() 
{
    fieldChangeNotify( 0 );
}

You will then be able to use a FieldChangeListener exactly as you are now, but the image button will not call it unless the click occurs on your button.

If you want, you can certainly change the code above to use

    fieldChangeNotify( 1 );

if 1 is a meaningful context value for you. The important thing is to add the other methods, and change navigationClick().

于 2013-05-15T08:46:45.483 回答