3.6 高级屏幕类综合应用实例
3.6.1 Form组件综合练习
【例3-14】 Form组件综合练习。前面已经学习了所有的Form组件,这里将所有的组件都集中放置在Form界面上,进行综合练习。
import javax.microedition.midlet.*; import javax.microedition.lcdui.*; public class mainMidlet extends MIDlet implements CommandListener{ private Form mainscreen; private Command okCommand = new Command("OK", Command.OK, 1); private Command exitCommand = new Command("Exit", Command.EXIT, 1); private Display display; public mainMidlet() { mainscreen= new Form("Form demo"); mainscreen.addCommand(okCommand); mainscreen.addCommand(exitCommand); mainscreen.setCommandListener(this); //创建StringItem对象 mainscreen.append(new StringItem("StringItem Test", "The following is Duke.")); //创建ImageItem对象 Image img=null; try { img= Image.createImage("/smallDuke.png"); } catch (Exception e) {} mainscreen.append(new ImageItem("ImageItem test", img, ImageItem.LAYOUT_CENTER, "Image can not display")); //创建Choice对象 String[] editable_choices={"editable", "uneditable"}; mainscreen.append(new ChoiceGroup("Gauge option",Choice.EXCLUSIVE, editable_choices,null)); //创建TextField对象 mainscreen.append(new TextField("TextField", "", 20, TextField. ANY)); //创建DateField对象 mainscreen.append(new DateField("DateField", DateField.DATE)); //创建Gauge对象 mainscreen.append(new Gauge("Gauge Test",true,100,50)); //创建Display对象 display=Display.getDisplay(this); } public void startApp() throws MIDletStateChangeException { display.setCurrent(mainscreen); public void pauseApp() { } public void destroyApp(boolean unconditional) { //清除所有对象 mainscreen=null; okCommand = null; exitCommand = null; display=null; } public void commandAction(Command c, Displayable d) { if(c==okCommand) { //事件响应 } else if(c==exitCommand) { //退出程序 destroyApp(true); notifyDestroyed(); } } }
执行效果如图3-26所示。
图3-26 Form组件综合应用效果图
3.6.2 生物钟软件
1.游戏设计思想
人体生物钟的节律特征如表3-19所示。
表3-19 人体生物钟的节律特征
节律的计算公式:
Y=X%N:Y是节律,X是总天数,N是节律周期。
体力节律:Y1=X%23
情绪节律:Y2=X%28
智力节律:Y3=X%33
·当Y=0或Y=1或(N/2-1)<=Y<=(N/2+1)时,人体处于临界日;
·当Y<N/2时,且不是临界日,人体则处于高潮期;
·当Y>N/2时,且不是临界日,人体则处于低潮期。
游戏规则:游戏者输入出生日期,系统检测出游戏者当日的体力、情绪和智力方面的生理现象。
2.游戏设计流程
生物钟软件设计流程图如图3-27所示。
图3-27 生物钟软件流程图
3.游戏设计的难点和解决方法
(1)如何计算天数。
Date Date;=datefield.getDate() Long temp=System.currenttimeMillis-date.getTime(); Long X=temp/24/60/60/1000;
(2)重置游戏。
将3个StringItem清空或者设成无检测即可:
si1.setText(""); si2.setText(""); si3.setText("");
4.程序的完整代码
import java.util.Date; import javax.microedition.lcdui.*; import javax.microedition.midlet.*; public class ClockMidlet extends MIDlet implements CommandListener { Form f; DateField df; StringItem si1; StringItem si2; StringItem si3; Command exitCommand; Command checkCommand; Command restartCommand; public ClockMidlet() { super(); f=new Form("生物钟"); df=new DateField("出生日期",DateField.DATE); si1=new StringItem("体力",""); si2=new StringItem("情绪",""); si3=new StringItem("智力",""); exitCommand=new Command("退出",Command.EXIT,1); checkCommand=new Command("检测",Command.OK,2); restartCommand=new Command("重置",Command.OK,2); f.addCommand(exitCommand); f.addCommand(checkCommand); f.addCommand(restartCommand); f.append(df); f.append(si1); f.append(si2); f.append(si3); f.setCommandListener(this); } protected void destroyApp(boolean arg0) { } protected void pauseApp() {} protected void startApp(){ Display.getDisplay(this).setCurrent(f); } public void commandAction(Command cmd, Displayable arg1) { if(cmd==checkCommand) { Date date=df.getDate(); long temp=System.currentTimeMillis()-date.getTime(); long X=temp/24/60/60/1000; long Y1=X%23; long Y2=X%28; long Y3=X%33; if(Y1==0||Y1==1||(Y1>=23/2-1&&Y1<=23/2+1)) //计算体力周期 si1.setText("易患疾病"); else if(Y1<23/2) si1.setText("体力充沛精力旺"); else si1.setText("体力不足易疲劳"); if(Y2==0||Y2==1||(Y2>=28/2-1&&Y2<=28/2+1)) //计算情绪周期 si2.setText("容易冲动"); else if(Y2<28/2) si2.setText("情绪高精神爽"); else si2.setText("情绪低心情烦"); if(Y3==0||Y3==1||(Y3>=33/2-1&&Y3<=33/2+1)) //计算智力周期 si3.setText("易出差错"); else if(Y2<33/2) si3.setText("思维敏捷反应快"); else si3.setText("反应迟钝记忆差"); }else if(cmd==exitCommand) //退出按钮 { destroyApp(false); notifyDestroyed(); }else if(cmd==restartCommand) //重置按钮 { si1.setText(""); si2.setText(""); si3.setText(""); } } }
5.执行效果如图3-28所示
图3-28 生物钟软件效果图
3.6.3 猜数字游戏设计
1.游戏设计思想
计算机随机产生不重复的四位数字,用户输入猜测的数字,根据所给反馈信息继续输入,直到正确或者到达最多次数失败为止。
(1)每次启动游戏,系统先随机生成一个四位数,每个数字不重复。
(2)游戏者有5次机会来猜出目标数,每次机会中,游戏者可以输入一个四位数,同样不允许重复,例如2334是错误的。
(3)游戏者输入后,单击“确定”按钮,系统给出判断信息,以文本形式出现,例如2A1B,即有2个数的位置正确和数字正确,1个数的位置错误但是数字正确。
(4)如果输入数与目标数完全正确则成功,若5次都没猜对,则失败。
2.游戏的设计流程
猜数字游戏设计流程图如图3-29所示。
图3-29 猜数字游戏流程图
3.游戏的制作难点和解决方法
(1)启动游戏后,如何生成四位不同的随机数。
Random随机类的用法如下。
构造方法:Random r=new Random();
常用方法:r.nextInt(); 生成一个随机整数,通常采用以下方法处理Math.abs(ran.nextInt()%10)生成10以内的整数。
private void initNum() { for(int i=0;i<4;i++) { n_Num[i]=Math.abs(ran.nextInt()%10); for(int j=i;j<i;j++) { if(n_Num[i]==n_Num[j]) //避免生成相 同的数字 { j--; break; } } } }
(2)如何判断游戏者输入的数字是合法的。
private boolean check(char[] a_Num) { if(tf.getString().length()!=4) //判断是否输入了四位数 return false; for(int i=0;i<4;i++) //判断是否输入了重复的数字 for(int j=i;j<4;j++) { if(a Num[i]==a_Num[j]&&i!=j) return false; } return true; }
(3)如何根据游戏者的输入给出反馈信息。
tf.getChars(c_aNum); //获取输入内容 if(check(c_aNum)) //判断输入内容是否正确的 { for(int i=0;i<4;i++) for(int j=0;j<4;j++) if((int)(c_aNum[i]-'0')==n_Num[j]) //进行对比,计算nA和nB { if(i==j) nA++; else nB++; } }
4.完整代码
import java.util.Random; import javax.microedition.lcdui.*; import javax.microedition.midlet.*; public class GuessMidlet extends MIDlet implements CommandListener { Display disp; Form form; TextField tf; StringItem si; Command cmdEnter; Command cmdExit; Random ran=new Random(); int[] n_Num=new int[4]; char[] c_aNum=new char[4]; public GuessMidlet() { disp=Display.getDisplay(this); form=new Form("猜数字"); tf=new TextField("输入数字","",4,TextField.NUMERIC); si=new StringItem("反馈信息",""); cmdEnter=new Command("确定",Command.OK,1); cmdExit=new Command("退出",Command.EXIT,1); form.append(tf); form.append(si); form.addCommand(cmdEnter); form.addCommand(cmdExit); form.setCommandListener(this); form.setCommandListener(this); initNum(); } private void initNum() { for(int i=0;i<4;i++) { n_Num[i]=Math.abs(ran.nextInt()%10); for(int j=i;j<i;j++) { if(n_Num[i]==n_Num[j]) { j--; break; } } } } protected void destroyApp(boolean arg0) throws MIDletStateChange Exception { } protected void pauseApp() { } protected void startApp() throws MIDletStateChangeException { disp.setCurrent(form); } private boolean check(char[] a_Num) { if(tf.getString().length()!=4) return false; for(int i=0;i<4;i++) for(int j=i;j<4;j++) {if(a_Num[i]==a_Num[j]&&i!=j) return false; } return true; } public void commandAction(Command cmd, Displayable d) { int nA=0; int nB=0; if(cmd==cmdExit) { try { destroyApp(false); } catch (MIDletStateChangeException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } notifyDestroyed(); } else if(cmd==cmdEnter) { tf.getChars(c_aNum); if(check(c_aNum)) { for(int i=0;i<4;i++) for(int j=0;j<4;j++) if((int)(c_aNum[i]-'0')==n_Num[j]) { if(i==j) nA++; else nB++; } } else { System.out.println("False"); } StringBuffer buffer=new StringBuffer(); buffer.append(nA); buffer.append("A"); buffer.append(nB); buffer.append("B"); si.setText(buffer.toString()); } } }
5.执行效果如图3-30所示
图3-30 猜数字游戏效果图
3.6.4 心理测试软件
1.游戏的设计思想
(1)用户根据问题选择答案,答完所有题目后单击“确定”按钮,根据所选答案给出心理测试的结果信息。
(2)第一个界面显示心理测试的问题。
(3)用户输入后,计算所得分数切换到第二个界面。
(4)第二个界面给出相应的信息,并且可以返回到第一个界面。
(5)第一个界面可以退出软件。
2.界面对象分析
(1)界面1:formAsk负责提出问题。
Form对象:
ChoiceGroup对象,负责给出问题和选项;
Command对象,负责退出和确定。
(2)界面2:formAnswer负责给出心理测试的答案。
Form对象:
Command对象,负责返回初始界面。
3.游戏的设计流程
心理测试软件设计流程图如图3-31所示。
图3-31 心理测试软件流程图
4.游戏的制作难点和解决方法
(1)计算得分。根据选项的序号设定得分:
int i=cg1.getSelectedIndex()+cg2.getSelectedIndex()+ cg3.getSelectedIndex()+cg4.getSelectedIndex()+cg5.getSelectedIndex();
(2)返回问题界面时同时清除答案界面的内容。
if(cmd==cmdBack){ disp.setCurrent(formAsk); formAnswer.deleteAll(); }
5.完整代码
import javax.microedition.lcdui.*; import javax.microedition.midlet.*; public class HeartMidlet extends MIDlet implements CommandListener { Display disp; Form formAsk,formAnswer; ChoiceGroup cg1,cg2,cg3,cg4,cg5; Command cmdEnter; Command cmdExit,cmdBack; public HeartMidlet() { disp=Display.getDisplay(this); formAsk=new Form("提问"); formAnswer=new Form("测试结果"); cg1=new ChoiceGroup("你想改变目前的生活状态么?",ChoiceGroup. EXCLUSIVE); cg1.append("想", null); cg1.append("无所谓", null); cg1.append("不想", null); cg2=new ChoiceGroup("你想改变目前的生活状态么?",ChoiceGroup. EXCLUSIVE); cg2.append("想", null); cg2.append("无所谓", null); cg2.append("不想", null); cg3=new ChoiceGroup("你想改变目前的生活状态么?",ChoiceGroup. EXCLUSIVE); cg3.append("想", null); cg3.append("无所谓", null); cg3.append("不想", null); cg4=new ChoiceGroup("你想改变目前的生活状态么?",ChoiceGroup. EXCLUSIVE); cg4.append("想", null); cg4.append("无所谓", null); cg4.append("不想", null); cg5=new ChoiceGroup("你想改变目前的生活状态么?",ChoiceGroup. EXCLUSIVE); cg5.append("想", null); cg5.append("无所谓", null); cg5.append("不想", null); cmdEnter=new Command("确定",Command.OK,1); cmdExit=new Command("退出",Command.EXIT,2); cmdBack=new Command("返回",Command.BACK,2); formAsk.append(cg1); formAsk.append(cg2); formAsk.append(cg3); formAsk.append(cg4); formAsk.append(cg5); formAsk.addCommand(cmdEnter); formAsk.addCommand(cmdExit); formAnswer.addCommand(cmdBack); formAsk.setCommandListener(this); formAnswer.setCommandListener(this); } protected void destroyApp(boolean arg0) { } protected void pauseApp() { } protected void startApp() throws MIDletStateChangeException { disp.setCurrent(formAsk); } public void commandAction(Command cmd, Displayable arg1) { if(cmd==cmdExit) { destroyApp(false); notifyDestroyed(); }else if(cmd==cmdBack){ disp.setCurrent(formAsk); formAnswer.deleteAll(); }else if(cmd==cmdEnter) { int i=cg1.getSelectedIndex()+cg2.getSelectedIndex()+ cg3.getSelectedIndex()+cg4.getSelectedIndex()+cg5.getSelectedIndex(); if(i<4) formAnswer.append("你处在比较积极的状态"); else if(i<6) formAnswer.append("你已经开始发懒了"); else if(i<8) formAnswer.append("你的惰性很大了"); else if(i<=10) formAnswer.append("你已经是懒骨头了"); disp.setCurrent(formAnswer); } } }
6.执行效果如图3-32所示
图3-32 心理测试软件效果图
3.6.5 电子书的制作
通过高级屏幕类阅读已经存储在程序中的诗词,重点是建立诗词目录界面及每首诗词的显示界面。
1.游戏功能
启动界面加载条,当加载结束后进入一级菜单,选项包括“唐诗鉴赏”和“宋词鉴赏”。根据选择进入相应的二级菜单,包括唐诗和宋词的题目,然后进入具体的内容阅读。
2.程序的构成
整个程序只有一个EBookMIDlet类,用来切换不同的显示内容。
本程序主要是通过高级屏幕类阅读已经存储在程序中的诗词,重点是建立诗词目录界面以及每首诗词的显示界面。
完整代码如下:
import javax.microedition.lcdui.*; import javax.microedition.midlet.MIDlet; public class EBookMIDlet extends MIDlet implements Runnable,CommandListener, ItemCommandListener{ /**屏幕显示对象*/ private Display display; /**加载提示*/ private Alert alert; /**加载条*/ private Gauge gauge; /**数目列表*/ private List list; /**章节列表*/ private Form form; /**书本内容*/ private TextBox textBox; /**初始时间*/ long firstTime; private Image image; private final Command cmdEnter = new Command("进入",Command.OK,1); private final Command cmdExit = new Command("退出",Command.EXIT,1); private final Command cmdBack = new Command("返回",Command.BACK,1); /**当前书目索引*/ private int curBookIndex = 0; /**书目*/ private String[] bookName = {"《唐诗鉴赏》","《宋词鉴赏》"}; /**二维字符串数组,用以每首诗词的序号、名称、作者及内容*/ private String[][] text = {{ "第一首","水调歌\n作者:无名氏\n","平沙落日大荒西,陇上明星高复低。\n孤山几处看烽火,壮士连营候鼓鼙。", "第二首","感遇四首之一\n作者:张九龄\n"," 孤鸿海上来,池潢不敢顾。\n侧见双翠鸟,巢在三珠树。\n矫矫珍木巅,得无金丸惧。\n美服患人指,高明逼神恶。\n今我游冥冥,弋者何所慕。", "第三首","春思\n作者:李白\n"," 燕草如碧丝,秦桑低绿枝。\n当君怀归日,是妾断肠时。\n春风不相识,何事入罗帏?", "第四首","夕次盱眙县\n作者:韦应物\n"," 落帆逗淮镇,停舫临孤驿。\n浩浩风起波,冥冥日沈夕。\n人归山郭暗,雁下芦洲白。\n独夜忆秦关,听钟未眠客。", "第五首","溪居\n作者:柳宗元\n"," 久为簪组累,幸此南夷谪。\n闲依农圃邻,偶似山林客。\n晓耕翻露草,夜榜响溪石。\n来往不逢人,长歌楚天碧。", "第六首","塞下曲\n作者:王昌龄\n"," 饮马渡秋水,水寒风似刀。\n平沙日未没,黯黯见临洮。\n昔日长城战,咸言意气高。\n黄尘足今古,白骨乱蓬蒿。", "第七首","子夜四时歌:春歌\n作者:李白\n"," 秦地罗敷女,采桑绿水边。\n素手青条上,红妆白日鲜。\n蚕饥妾欲去,五马莫留连。", "第八首","子夜四时歌:夏歌\n作者:李白\n"," 镜湖三百里,菡萏发荷花。\n五月西施采,人看隘若耶。\n回舟不待月,归去越王家。", "第九首","子夜四时歌:秋歌\n作者:李白\n","长安一片月,万户捣衣声。\n秋风吹不尽,总是玉关情。\n何日平胡虏,良人罢远征?", "第十首","子夜四时歌:冬歌\n作者:李白\n","明朝驿使发,一夜絮征袍。\n素手抽针冷,那堪把剪刀。\n裁缝寄远道,几日到临洮?", "第十一首","送别\n作者:王维\n","下马饮君酒,问君何所之。\n君言不得意,归卧南山陲。\n但去莫复闻,白云无尽时。"}, { "第一首","宴山亭.北行见杏花\n作者:赵佶\n","裁剪冰绡,轻叠数重,淡着燕脂匀注。\n新样靓妆,艳溢香融,羞杀蕊珠宫女。\n易得凋零,更多少、无情风雨。 愁苦,问院落凄凉,几番春暮?\n凭寄离恨重重,者双燕何曾,会人言语?\n天遥地远,万水千山,知他故宫何处?怎不思量?\n除梦里有曾去。无据,和梦也新来不做。", "第二首","木兰花\n作者:钱惟演\n","城上风光莺语乱,城下烟波春拍岸。\n绿杨芳草几时休?泪眼愁肠先已断。\n情怀渐觉成衰晚,鸾镜朱颜惊暗换。\n昔年多病厌芳尊,今日芳尊惟恐浅。", "第三首","苏幕遮\n作者:范仲淹\n","碧云天,黄叶地,秋色连波,波上寒烟翠。\n山映斜阳天接水,芳草无情,更在斜阳外。\n黯乡魂,追旅思。夜夜除非,好梦留人睡。\n明月楼高休独倚,酒入愁肠,化作相思泪。", "第四首","御街行\n作者:范仲淹\n","纷纷坠叶飘香砌。夜寂静,寒声碎。\n真珠帘卷玉楼空,天淡银河垂地。\n年年今夜,月华如练,长是人千里。\n愁肠已断无由醉,酒未到,先成泪。\n残灯明灭枕头[奇支],谙尽孤眠滋味。\n都来此事,眉间心上,无计相回避。", "第五首","千秋岁\n作者:张先\n","数声[是鸟][夫鸟],又报芳菲歇。\n惜春更选残红折,雨轻风色暴,梅子青时节。\n永丰柳,无人尽日花飞雪。莫把幺弦拨,怨极弦能说。\n天不老,情难绝,心似双丝网,中有千千结。\n夜过也,东窗未白孤灯灭。", "第六首","菩萨蛮\n作者:张先\n","哀筝一弄《湘江曲》,声声写尽湘波绿。\n纤指十三弦,细将幽恨传。 当筵秋水慢,玉柱斜飞雁。\n弹到断肠时,春山眉黛低。 醉垂鞭 张先双蝶绣罗裙,东池宴初相见。朱粉不深匀,闲花淡淡春。\n细看诸处好,人人道柳腰身。昨日乱山昏,来时衣上云。" } }; public EBookMIDlet() { display = Display.getDisplay(this); alert = new Alert("E-Book启动中",null,null,AlertType.INFO); gauge = new Gauge(null,false,5,1); alert.setIndicator(gauge); alert.setTimeout(6000); firstTime = System.currentTimeMillis(); image = createImage("/flag.png"); list = new List("书目",Choice.IMPLICIT,bookName,new Image[]{image, image}); list.addCommand(cmdEnter); list.addCommand(cmdExit); list.setCommandListener(this); new Thread(this).start(); //启动线程,将在之后的章节具体介绍 } private Image createImage(String file){ Image image = null; try{ image = Image.createImage(file); }catch(Exception e){ e.printStackTrace(); } return image; } protected void destroyApp(boolean arg0){ } protected void pauseApp() { } protected void startApp(){ display.setCurrent(alert); } /** * 控制进度提示 */ public void run() { // TODO Auto-generated method stub while(true){ int time = (int)(System.currentTimeMillis() - firstTime); gauge.setValue(time/1000); if(time >= alert.getTimeout()){ display.setCurrent(list); alert.setIndicator(null); break; } } } /** * 创建每首诗词显示在Form中的Item * @param label * @param text * @return */ private Item createItem(String label,String text){ Item item = new StringItem(label,text,Item.PLAIN); item.addCommand(cmdEnter); item.setItemCommandListener(this); return item; } /** * 创建显示诗词信息的Form * @param bookIndex * @return */ private Form createForm(int bookIndex){ Form form = new Form(bookName[bookIndex]); for(int i=0; i<text[bookIndex].length/3; i++){ form.append(createItem(text[bookIndex][i*3+0],text[bookIndex] [i*3+1])); } form.addCommand(cmdBack); form.setCommandListener(this); return form; } /** * 创建诗词显示的TextBox * @param title * @param text * @return */ private TextBox createTextBox(String title,String text){ TextBox textBox = new TextBox(title,text,200,TextField.ANY); textBox.addCommand(cmdBack); textBox.setCommandListener(this); return textBox; } /** * 各个窗体事件 */ public void commandAction(Command command, Displayable displayable) { if(command == cmdEnter){ if(displayable.equals(list)){ curBookIndex = list.getSelectedIndex(); form = createForm(curBookIndex); display.setCurrent(form); } }else if(command == cmdBack){ if(displayable.equals(form)){ display.setCurrent(list); }else if(displayable.equals(textBox)){ form = createForm(curBookIndex); display.setCurrent(form); } }else if(command == cmdExit){ notifyDestroyed(); destroyApp(true); } } /** * 得到当前所选的诗词索引号 * @param indexText * @return */ public int getIndex(String indexText){ for(int i=0; i<text[curBookIndex].length/3; i++){ if(indexText.equals(text[curBookIndex][i*3+0])) return i; } return -1; } /** * ItemCommandListener事件,显示当前所选诗词的内容 */ public void commandAction(Command command, Item item) { if(command == cmdEnter){ int num = getIndex(item.getLabel()); if(num == -1) return; textbox = createTextBox(text[curBookIndex][num*3+0]+text [curBookIndex][num*3+1], text[curBookIndex][num*3+1]+text[curBookIndex][num*3+2]); display.setCurrent(textBox); } } }
执行效果如图3-33所示。
图3-33 电子书效果图
3.6.6 字母拼图
1.游戏功能
启动界面出现4×4的字母块,单击“开始”按钮,将字母块打乱,通过上、下、左、右方向键将字母块拼回到起始界面,显示胜利的信息。
2.程序的构成
整个程序由3个类构成,分别是:
·mainMidlet类:程序的入口,调用MyCanvas对象;
·StringBlock类:定义字母块的结构,包括坐标,字母内容及是否反显;
·myCanvas类:程序的主要类,实现字母的初始化、字母的显示、键盘响应、字母的移动。
(1)mainMidlet类。
import javax.microedition.lcdui.Display; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; public class mainMidlet extends MIDlet { private static mainMidlet instance; public mainMidlet() { instance=this; } protected void destroyApp(boolean arg0) { } protected void pauseApp() { } protected void startApp() throws MIDletStateChangeException { Display.getDisplay(this).setCurrent(new myCanvas()); } public static void quit(){ instance.destroyApp(false); instance.notifyDestroyed(); instance=null; } }
(2)StringBlock类。
public class StringBlock { int ox,oy; int x,y; char word; boolean inv; }
(3)myCanvas类。
import java.util.Random; import javax.microedition.lcdui.*; //Canvas类的子类,负责手机画面的内容和响应逻辑 public class myCanvas extends Canvas implements Runnable, CommandListener { int scrW,scrH; //屏幕的宽和高 Thread th; //线程类 StringBlock sb[],blank; //字母块及空白块 boolean winstate; //是否胜利 /* * 负责初始化变量 */ public myCanvas() { scrW=getWidth(); scrH=getHeight(); String sbstring="J2MEJAVAVC++SQL "; sb=new StringBlock[16]; //利用循环生成4×4的字母块 for(int i=0;i<16;i++){ sb[i]=new StringBlock(); sb[i].ox=i%4; //字母块的行数 sb[i].oy=i/4; //字母块的列数 sb[i].x=sb[i].ox; sb[i].y=sb[i].oy; if(sb[i].oy>=2) sb[i].inv=true; else sb[i].inv=false; sb[i].word=sbstring.charAt(i); } blank=sb[15]; blank.inv=false; winstate=false; addCommand(new Command("Exit",Command.EXIT,1)); addCommand(new Command("Start",Command.OK,1)); setCommandListener(this); th=new Thread(this); } /* * 负责绘制屏幕内容 */ protected void paint(Graphics g) { //清屏三句话 g.setColor(255,255,255); g.fillRect(0,0,scrW,scrH); g.setColor(0); //具体绘制内容 Font ft=Font.getFont(Font.FACE_MONOSPACE,Font.STYLE_PLAIN,Font. SIZE_MEDIUM); int wordw=ft.charWidth('M'); int wordh=ft.getHeight(); int pad=4; int gpad=2; int allw=(wordw+pad*2)*4+gpad*5; int allh=(wordh+pad*2)*4+gpad*5; //绘制外框线 g.setColor(0); g.drawRect((scrW-allw)/2, (scrH-allh)/2, allw,allh); //绘制具体内容 int x,y,dx,dy; for(int i=0;i<16;i++){ x=sb[i].x;y=sb[i].y; dx=(scrW-allw)/2+(x+1)*gpad+x*(wordw+pad*2); dy=(scrH-allh)/2+(y+1)*gpad+y*(wordh+pad*2); if(sb[i].inv){ g.setColor(0); g.fillRect(dx,dy,wordw+pad*2,wordh+pad*2); dx+=pad; dy+=pad; g.setColor(0xffffff); g.drawChar(sb[i].word,dx,dy,20); } else { g.setColor(0); g.drawRect(dx,dy,wordw+pad*2,wordh+pad*2); dx+=pad; dy+=pad; g.drawChar(sb[i].word,dx,dy,20); } } //当胜利时绘制胜利信息 if(winstate){ g.setColor(0xff); g.drawString("You Win!",scrW/2,scrH-20,20); } } /* * 负责键盘响应 */ protected void keyPressed(int key) { //把输入的键盘码转换成游戏码 int k=getGameAction(key); //对转换的游戏码进行分析 switch(k) { case UP: //如果是按下向上键有什么反应 moveBlock(0); break; case DOWN: moveBlock(1); break; case LEFT: moveBlock(2); break; case RIGHT: moveBlock(3); break; } if(isSolved()) winstate=true; repaint(); //千万不要忘了重绘命令 } //判断是否所有字母块都归位 private boolean isSolved() { int i=0; while(i<16) { if((sb[i].ox==sb[i].x)&&sb[i].oy==sb[i].y) i++; else return false; } return true; } //移动字母块,根据方向让字母块和空白块交换 private void moveBlock(int i) { StringBlock temp = null; switch(i){ case 0: temp=findBlock(blank.x,blank.y+1); break; case 1: temp=findBlock(blank.x,blank.y-1); break; case 2: temp=findBlock(blank.x+1,blank.y); break; case 3: temp=findBlock(blank.x-1,blank.y); break; } if(temp==null)return; swapblock(temp,blank); } private void swapblock(StringBlock a, StringBlock b) { int x,y; x=a.x; y=a.y; a.x=b.x; a.y=b.y; b.x=x; b.y=y; } private StringBlock findBlock(int x, int y) { StringBlock temp=null; for(int i=0;i<16;i++) { if(sb[i].x==x&&sb[i].y==y) { temp=sb[i]; break; } } return temp; } public void run() { while(true){ repaint(); try { Thread.sleep(200); } catch (InterruptedException e) { // TODO 自动生成 catch 块 e.printStackTrace(); } } } public void commandAction(Command cmd, Displayable arg1) { switch(cmd.getCommandType()) { case Command.EXIT: mainMidlet.quit(); break; case Command.OK: winstate=false; daluan(); break; } } //将字母块的顺序打乱 private void daluan() { int j; Random rd=new Random(); StringBlock temp; for(int i=0;i<140;i++){ j=Math.abs(rd.nextInt())%4; moveBlock(j); } while(blank.x<3) moveBlock(2); while(blank.y<3) moveBlock(0); repaint(); } }
3.执行效果如图3-34所示
图3-34 字母拼图效果图