【问题标题】:How to store an image in persistent store如何将图像存储在持久存储中
【发布时间】:2012-11-15 03:33:32
【问题描述】:

我正在开发具有“图像按钮”的 BlackBerry 应用程序。 “图像按钮”可以在每次点击之间从“开”变为“关”,反之亦然。现在我要做的是,当应用程序关闭并再次加载时,这个“图像按钮”应该作为最后一个状态加载。如果“图像按钮”设置为“开”并且应用程序关闭,则在下次加载时它将加载为“开”。创建图像按钮时,如果该值设置为“true”,则图像加载为“ON”,即使它被创建为 off-on。我在构造函数之外创建了 ImageButton:

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

然后在构造函数中,我尝试检查最后一个图像状态并相应地再次创建图像按钮。但是, (boolean)((Boolean) persistentHashtable.get("image")).booleanValue() 会抛出 CastException,即使它编译正常。

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);
     }
 }

我在退出时保存图像的状态:

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;
    }

请指导。作为参考,下面是用于创建图像按钮的 LabeledSwitch 类:

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);
        }
    };
}

【问题讨论】:

  • 请说明您当前的输出是什么?
  • 正常的做法是保存状态,然后在启动时根据保存的状态初始化按钮。相反,您正在尝试持久化 GUI 组件。
  • 为了扩展史密斯先生的出色评论,为了保存对应于 2 状态 UI 按钮/开关的状态,通常您只需保存一个 Boolean 值(TRUEFALSE )。这是最干净的实现。也就是说,将状态保存为图像文件名当然应该可能,因此您的问题可能在其他地方。
  • 使用persistentHashtable.put("image", Boolean.TRUE) 将状态保存为简单的Boolean。当您重新读取状态时,如果保存的值为Boolean.TRUE,则使用“on.png”作为您的图像。关于您发布的代码,第一个大块是所有代码块,还是您在那里粘贴了多个方法的代码?你打电话给persistentHashtable.put("image", ...),然后立即测试persistentHashtable.containsKey("image"),这对我来说没有意义。该测试永远不会像您编写的那样失败。
  • 但是,调用setOn() 方法将告诉LabeledSwitch 是显示on 还是off 图像。 on 状态的开关不应该与 off 状态的开关具有相同的_imageOn_imageOff 值吗?这应该只是显示哪个图像的问题,这取决于您调用setOn() 时设置的标志。正确的?另外,当我使用持久对象 API 时,我总是调用 commit()

标签: blackberry persistent persistent-storage


【解决方案1】:

所以,我认为这里可能存在多个问题。我确实认为 Eugen 关于commit() 的电话是正确的。

但是,我认为 LabeledSwitch 类的使用不正确。我猜你没有写那门课?我之所以这么说,是因为我在这一类中看到了多种编码约定。

见过多个这样的自定义 BlackBerry UI 类,我相信这是该类应该工作的方式:

  1. 该类可以在两种视觉状态之间切换,您可以通过向该类传递一个代表 on 状态和 off 状态的 PNG 图像来定义这种状态.

  2. 可以通过调用setOn() 方法在这些状态之间切换类,参数为truefalse 值。该参数的值将决定在该类的自定义paint() 方法中绘制哪个PNG 文件

  3. 该类的原作者打算让您使用setOn()getOnState() 方法来修改和访问开关的当前状态。你应该改变这个

public boolean _on;

到这里:

private boolean _on;

如果您想知道开关是否打开,请询问onImg.getOnState()

顺便说一句,我会为您的交换机推荐一个不同于onImg 的名称。这是一个非常混乱的名字。它应该类似于onOffSwitch,或toggleSwitch,或fooSwitch,如果开关用于关闭和打开名为foo 的东西。在成员变量_imageOn 的上下文中,将其命名为onImg 会造成混淆,它应该始终 表示开关on 时显示的图像。 p>

所以,总结一下,而不是这样:

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

使用这样的东西:

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

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

【讨论】:

    【解决方案2】:

    首先,我没有看到存储持久对象所需的以下代码:

    persistentObject.commit();
    

    我希望这只是您代码中的一些额外内容,否则您总是在阅读之前重写值,这可能不是预期的。所以'读'代码不应该留在'写'之后,因为它没有任何意义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-27
      • 2017-08-30
      相关资源
      最近更新 更多