سؤال

I am working on a BlackBerry application that has an "Image Button". The "Image Button" can change from "ON to OFF" and vice versa between each clicks. Now what I am trying to do is, when the app is closed and loaded again, this "Image Button" should load as its last state. If the "Image Button" was set to "ON" and the app closed, on next load it will load as "ON". When creating the Image Button, if the value is set to "true", the image loads as "ON" even though it was created as off-on. I create the ImageButton outside the constructor:

LabeledSwitch onImg=new LabeledSwitch(off,on,off,on,true); 

Then inside the constructor, I tried to check the last image state and so create the Image Button again accordingly. However, (boolean)((Boolean) persistentHashtable.get("image")).booleanValue() throws a CastException even though it compiles alright.

persistentObject = PersistentStore.getPersistentObject(KEY);

 if (persistentObject.getContents() == null) 
 {
    persistentHashtable = new Hashtable();
    persistentObject.setContents(persistentHashtable);
 } else {
    persistentHashtable = (Hashtable) persistentObject.getContents();
     }

  if (persistentHashtable.containsKey("image")) 
 {
     boolean booleanVal = (boolean)((Boolean) persistentHashtable.get("image")).booleanValue();
     if (booleanVal==true)
     {
         onImg=new LabeledSwitch(on,off,on,off,true);
     }
     else
     {
         onImg=new LabeledSwitch(off,on,off,on,false);
     }
 }

I am saving the state of the image on exit:

public boolean onClose() 
    {
        int choose=Dialog.ask(Dialog.D_YES_NO, "Are you sure Want to Exit?");
        if(choose==Dialog.YES)
        {
            if(onImg._on)
             persistentHashtable.put("image", Boolean.TRUE);

            else
                persistentHashtable.put("image", Boolean.FALSE); 
            System.exit(0);

        }
        return true;
    }

Please guide. For reference, below is the LabeledSwitch class used to create the image button:

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

public class LabeledSwitch extends Field {
    private String _textOn;
    private String _textOff;

    private int _textWidth;
    private int _textHeight;

    private int _totalWidth;
    private int _totalHeight;

    private Bitmap _imageOn;
    private Bitmap _imageOnFocus;
    private Bitmap _imageOff;
    private Bitmap _imageOffFocus;

    public boolean _on; //chngd
    private boolean _selected;

    private Font _labelFont;

    private static MenuItem _changeOptionsItem = new ChangeOptionMenuItem();

    private int _textColour = 0x888888;
    private int _textColourFocus = 0x000000;

    private int _horizontalTextImageGap;

    private Bitmap _switchImage;  
    private String _labelText;  
    int mHeight;
    int mWidth;

    public LabeledSwitch(){}

    public LabeledSwitch( Bitmap imageOn
                , Bitmap imageOff
                , Bitmap imageOnFocus
                , Bitmap imageOffFocus
                , boolean onByDefault ) {
        super( Field.FIELD_VCENTER );

        //_textOn = textOn ="";
        //_textOff = textOff ="";

        _imageOn = imageOn;
        _imageOff = imageOff;
        _imageOnFocus = imageOnFocus;
        _imageOffFocus = imageOffFocus;
        _on = onByDefault; 
        _selected = false;

        _horizontalTextImageGap = _imageOn.getHeight() / 3;

    }

    public void applyFont() {
        _labelFont = getFont().derive( Font.PLAIN, _imageOn.getHeight()  );
    }

    /**
     * Change the state of the switch
     * @param on - if true, the switch will be set to on state
     */
    public void setOn(boolean on) {
        _on = on;
        invalidate();
    }

    public boolean getOnState() {
        return _on;
    }

    public boolean isFocusable() {
        return true;
    }

    public int getPreferredWidth() {
        return _totalWidth;
    }

    public int getPreferredHeight() {
        return _totalHeight;
    }

    protected void layout( int width, int height ) {
        // 
        _textWidth = Math.max( _labelFont.getAdvance( _textOn + "a" ), _labelFont.getAdvance( _textOff + "a" ) )-36;
        _textHeight = _labelFont.getHeight();

        _totalWidth = _imageOn.getWidth() + _horizontalTextImageGap + _textWidth;
        _totalHeight = _imageOn.getHeight();

        mWidth = getPreferredWidth();
        mHeight = getPreferredHeight();
        setExtent(mWidth, mHeight);

       // setExtent( _totalWidth, _totalHeight );
    }

    public void paint( Graphics g ){
        Font oldFont = g.getFont();
        int oldColor = g.getColor();

        try { 

            if( _on ) {
                _switchImage = g.isDrawingStyleSet(Graphics.DRAWSTYLE_FOCUS) ? _imageOnFocus : _imageOn;
            } else {
                _switchImage = g.isDrawingStyleSet(Graphics.DRAWSTYLE_FOCUS) ? _imageOffFocus : _imageOff;
            }

            g.setFont( _labelFont );

            // Determine Label Colour
            g.setColor( g.isDrawingStyleSet(Graphics.DRAWSTYLE_FOCUS) ? _textColourFocus : _textColour );

            // Label
            g.drawText( _on ? _textOn : _textOff, 0, ( getHeight() - _textHeight ) / 2, DrawStyle.RIGHT, _textWidth ); 

            // Image
            //g.drawBitmap( _textWidth + _horizontalTextImageGap, 0, _switchImage.getWidth(), _switchImage.getHeight(), _switchImage, 0, 0 );
            g.drawBitmap(0, 5, mWidth, mHeight, _switchImage, 0, 0);
        } finally {
            g.setFont( oldFont );
            g.setColor( oldColor );
        }
    }

    public void paintBackground( Graphics g ) {}

    protected void drawFocus( Graphics g, boolean on ){
        // Paint() handles it all
        g.setDrawingStyle( Graphics.DRAWSTYLE_FOCUS, true );
        paint( g );
    }

    protected boolean keyChar( char key, int status, int time ){
        if( key == Characters.SPACE || key == Characters.ENTER ) {
            toggle();            
            return true;
        }
        return false;
    }

    protected boolean navigationClick(int status, int time){
        toggle();            
        return true;    
    }

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

    protected boolean trackwheelClick( int status, int time ){        
        if( isEditable() ) {
            toggle();            
            return true;
        }
        return super.trackwheelClick(status, time);
    }

    /**
     * Toggles the state of the switch
     */
    private void toggle(){
        _on = !_on;
        invalidate();
        fieldChangeNotify( 0 );
    }

    public void setDirty( boolean dirty ){
        // We never want to be dirty or muddy
    }

    public void setMuddy( boolean muddy ){
        // We never want to be dirty or muddy
    }    

    protected void makeContextMenu(ContextMenu contextMenu){
        super.makeContextMenu(contextMenu);
        if((Ui.getMode() < Ui.MODE_ADVANCED) && isEditable()) {
            contextMenu.addItem(_changeOptionsItem);
        }
    }

    /**
     * @category Internal InnerClass
     */
    static class ChangeOptionMenuItem extends MenuItem {
        ChangeOptionMenuItem() {
            super("Toggle", 30270, 10);
        }

        ChangeOptionMenuItem(String text) {
            super(text, 30270, 10);
        }

        public void run() {
            LabeledSwitch theSwitch = (LabeledSwitch)getTarget();
            theSwitch.toggle();
        }

        public int getPriority() {
            return 100 + (getTarget().isMuddy() ? 1000 : 0);
        }
    };
}
هل كانت مفيدة؟

المحلول

So, I think there may be multiple problems here. I do think Eugen is right about the commit() call.

However, I think the LabeledSwitch class is being used incorrectly. I'm going to guess that you didn't write that class? I only say that because I see multiple coding conventions within that one class.

Having seen multiple custom BlackBerry UI classes like this, I believe that this is the way that class is supposed to work:

  1. The class can toggle between two visual states, which you can define by passing the class a PNG image that represents the on state, and the off state.

  2. The class can be toggled between those states by calling the setOn() method, with either a true or false value for the parameter. The value of that parameter will determine which PNG file is drawn in the class's custom paint() method

  3. The class's original author intends for you to use the setOn() and getOnState() methods to modify and access the current state of the switch. You should change this

public boolean _on;

to this:

private boolean _on;

If you want to know if the switch is on, ask onImg.getOnState().

By the way, I would recommend a different name for your switch than onImg. That's a very confusing name. It should be something like onOffSwitch, or toggleSwitch, or fooSwitch, if the switch is used to switch off and on something called foo. Naming it onImg is confusing, in the context of the member variable _imageOn, which should always represent the image that gets displayed when the switch is on.

So, to summarize, instead of this:

 if (booleanVal==true)
 {
     onImg=new LabeledSwitch(on,off,on,off,true);
 }
 else
 {
     onImg=new LabeledSwitch(off,on,off,on,false);
 }

use something like this:

 onOffSwitch = new LabeledSwitch(on, off, on, off, true);
 onOffSwitch.setOn(booleanValue);        

or

 onOffSwitch = new LabeledSwitch(on, off, on, off, booleanValue);

نصائح أخرى

First of all, I don't see the following required code to have your persistent object stored:

persistentObject.commit();

I hope this is just several extras from your code, otherwise you always rewrite value before reading it, which is probably not expected. So the 'read' code should not stay after 'write', because it doesn't have any sense.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top