先说界面导航问题
每次看到那个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]);
}
}
}