《读艺》开发志(二)

类别:Java 点击:0 评论:0 推荐:

 先说界面导航问题

每次看到那个menu就感觉很不爽,可能是me怪癖,但仅仅为了找到某个功能按钮就需要按下“MENU”,进入选项窗口(注意当前浏览的页面被遮盖),找到需要的功能键,按下,然后出现结果,多麻烦呀。


 MENU的出现是因为对当前displayable(子类分别是Screen和Canvas)加入的命令Command多于两个(起码对一般的手机来说这个数字是两个,据java docs介绍也有可以容纳三个soft button的,me暂时没有见过,先不做考虑的说)。这样,要想不出现“MENU”,当前displayable只能加入两个Command。但是要实现一个完整的读书程序,仅仅两个Command肯定是不够的。me的解决思路是定义一个Command list存放命令列,displayable上只加入两个Command(以后统称屏显Command),然后通过按键对命令列进行轮循来实现功能按钮的查阅。左侧的屏显Command固定为操作帮助,介绍操作方法,因为这个界面导航的更新对大部分朋友来讲肯定不会马上适应,呵呵;另外一侧的屏显Command,具体来说就是按下手机上右方向键,自动换为命令列的下一个Command,左键则自动换为上一个Command。呵呵,简单吧


 如何实现确实是个难题。me以为网上应该有此类文章的,搜了半天,google出了一大堆结果,有用的不多,直接有用的几乎没有。不过mingjava的一篇“应用MVC设计模式解决J2ME应用程序导航问题 ”(http://blog.csdn.net/mingjava/archive/2004/06/29/30053.aspx)看起来好像很对题。仔细学习了一下,看不懂的居多,中间好像设计设计模式问题,这可不是me目前的水平可以承受的了的,呵呵。不过中间谈到把Midlet作为参数传入控制器的参数对me启发不小。


 “读艺”程序的类参考一般j2me程序是这样的一个构成模式,继承自MIDlet的主类ReadArt,继承自Canvas的子类ArtField(不好意思,仍然脱胎于那个Timer例程,所以叫做……Field,嘿嘿)作为主现实画布,和一个自定义的Article类用于组织文本,以及其他辅助类。翻了一下docs,Displayable不支持针对手机键盘的操作,也就是说诸如按下某键对Command进行改变好像不行。因此要实现对命令列的轮循,只能在Canvas中实现,因为Canvas有对键动作的接口keyPressed。通过对键值的查询可以知道是哪个键按下了,然后做出相应的改变就行了。至于命令列的传递通过ArtFiled的构建参数实现,即在ReadArt中定义commandlist,然后在生成ArtField的时候作为构建器参数传入,然后在ArtField的keyPressed中对commandlist进行操作。


 查阅docs,发现Canvas可以直接实现CommandListener。马上动手实现,但是在显示的时候却不能正确显示,不知道是Canvas对CommandListener的支持有限还是me没有找到合适的方法。另外,这时候me才发现Command居然不支持setLabel,也就是说一旦生成label就是不可更改的了。这样只好把命令列中的命令全部构建好,然后再调用。另外Canvas支持addCommand和removeCommand,这就好办咯,呵呵。综合以上问题,me调整了策略。构造时先显示“帮助”和另外一个默认的“下一页”(因为这个最常用),然后通过Canvas的keyPressed对屏显Command进行改变,方法是先removeAllCommand,然后在添加按照逻辑顺序的下一个或者上一个Command。测试,OK,呵呵。暂告一段落吧。具体代码样本如下:
 
 /**
 * ReadArt,看书软件的主程序
 * @author  heart5
 * @version start
 */
public class ReadArt extends MIDlet implements CommandListener{
    Display display;
    ArtField artf;
    About about;
    String[] cmdStrs = {"帮助","下一页","上一页","相关信息","退出"};
    Command cmds[];
    ……
   
    public ReadArt() {
        display = Display.getDisplay(this);
       
        cmds =new Command[cmdStrs.length];
        for(int i = 0; i < cmdStrs.length;i++){
            cmds[i] = new Command(cmdStrs[i],Command.SCREEN,1);
        }
       
        about = new About("操作指南","该软件的操作帮助信息如下:heart5");
       
        artf = new ArtField(cmds);
       
        artf.addCommand(cmds[1]);
        artf.addCommand(cmds[0]);
        artf.setCommandListener(this);
    }
   
    public void startApp() {
        display.setCurrent(artf);
        timer.schedule(mover,100,200);
    }
   
……
    public void commandAction(Command c, Displayable d){
        System.out.println(c.getLabel());
        if(c.getLabel().equals("退出")){
            destroyApp( true );
            notifyDestroyed();
        }else if(c.getLabel() .equals( "帮助"))
        {
            about.showAbout(display);
        }
    }
   
        public class Mover extends TimerTask {
       
        public void run() {
           artf.scroll();
        }
       
    }
}

……………………………………………………
/**
 * Canvas类型,生成画布用于显示文字
 * @author heart5
 * @version start
 */
class ArtField extends Canvas {
……
    /**
     * 构建器
     * @param cmds 命令串,自外部传入用于键动作时控制
     */
    public ArtField(Command[] cmds) {
        this.cmds = cmds;
……
    }
……
    /**
     * 键按下
     * @param keyCode 键值码
     */
    protected void keyPressed( int keyCode ) {
        int gameAction = this.getGameAction(keyCode);
        System.out.println(getKeyName(keyCode));
        int idx;
        switch (gameAction) {
            case RIGHT:
                this.removeAllCmd();
                idx = (cmdIndex + cmds.length -1) %(cmds.length-1) +1 ;
                this.addCommand(cmds[idx]);
                cmdIndex = idx;
               
                this.addCommand(cmds[0]);
                break;
            case LEFT:
                this.removeAllCmd();
                idx = (cmdIndex +1+cmds.length) %(cmds.length -1) +1 ;
                this.addCommand(cmds[idx]);
                cmdIndex = idx;
               
                this.addCommand(cmds[0]);
                break;
            case DOWN:
……
            default:
                pause = false;//确认键和其它键屏幕继续移动
        }
        repaint();
    }
    /**
     * 删除所有的命令,辅助方法
     */
    void removeAllCmd(){
        for(int i = 0 ; i < cmds.length ; i++){
            this.removeCommand(cmds[i]);
        }
    }
       
}

本文地址:http://com.8s8s.com/it/it14330.htm