J2ME中使用Canvas制作简单的游戏菜单 我们知道MIDP的图形用户界面分为两类,分别是高级图形用户界面和低级用户界面。一般来讲高级图形用户界面类使用起来比较方便,可移植性强,但是程序员对他的控制能力也很低,因为它们的界面表现是由底层控制的,而不是我们控制的。相比高级UI类,低级UI类则使用起来更难一些,但是控制能力更强,可以做出自己需要的界面。 帓?*藑 钉j糩畠 Canvas和Graphics是我们必须熟练使用的两个类,分别代表了画布和画笔(事实上更丰富,姑且这么比喻)。而我们则是画画的人,而指导我们如何下笔的就是java doc了,再加上勤奋努力一定可以画出不错的界面。比如tabbed菜单,二级菜单等。这里我们讲述一个简单菜单的制作方式。 \幢v?胖柇 摻€R碢[/9 在画菜单的时候,需要考虑两面的问题,第一是计算相对位置,让菜单能够尽可能适应更多的机型,尽量少使用绝对值。例如画下面的菜单的时候 ]DPa;5A 輿8揲?` 我们应该计算菜单的每个条目的高度,这些可以有Font的高度算出,当然你可以给条目留一些padding的距离。还应该计算条目的最宽值,毕竟每个条目的字数不一样。这样基本知道了整个菜单占的空间。最后还需要计算菜单在屏幕的位置。菜单的绘制如下所示: TKf楱祸i j喕I鶎逊{? public void paint(Graphics g){ 1湌.趈? +?G‘,Y?? //清除屏幕 產/兢覱?: 縏臢鲮 int color = g.getColor(); 佂膴lPI请T 9R逖篂p#0` g.setColor(0xFFFFFF); 癚コM緪聯 躪>?恩:? g.fillRect(0,0,getWidth(),getHeight()); 3迟9hz鸿蕋 }l?鎬A g.setColor(color); D嘣?)赿 D f领@晳夙 //计算整个菜单的高度,宽度和(x,y) db硵]孨 帧e(~|F:eI int rectWidth = preferWidth; O陮煫剄p$u 珀+砦0?@? int rectHeight = preferHeight * LABELS.length; fo?n@7]/ 矡鴃? int x = (getWidth()-rectWidth)/2; 鮃懇q憕? 罎诬| 饜7 int y = (getHeight()-rectHeight)/2; 豅?執N pA 硒+y?聽? //画矩形 €亶橳投? ??LZ柌? g.drawRect(x,y,rectWidth,rectHeight); ?O懙↙验7 琾?醃;l3 for(int i = 1;i<LABELS.length;i++){ zX_洤?徸: 钲vユ?? g.drawLine(x,y+preferHeight*i,x+rectWidth,y+preferHeight*i); |0?‘愓l, 婳見~紌? } 讏X?j-蝹 V爔? //画菜单选项,并根据selected的值判断焦点 郏/釄嫙m@ R崭?┅骑 for(int j = 0;j<LABELS.length;j++){ ▎A疭?? ?鹤? if(selected == j){ t?m挧? I-??淗 g.setColor(0x6699cc); R憄?o9tq md`_間隩_ g.fillRect(x+1,y+j*preferHeight+1,rectWidth-1,preferHeight-1); 妽G)?!揔$? 磫橅f棂﨤V g.setColor(color); 嵜*H癷儩? ;縃‘P? ? } 藤果槇櫫? u訐BiO? g.drawString(LABELS[j],x+8,y+j*preferHeight+4,Graphics.LEFT|Graphics.TOP); 時滊H[m昜 獇BD蚀拆? } 3z壜5圭#? ^姄~3q,H? } 迡I?R$? Eb?6M 第二个重要的问题是:焦点的切换,在高级UI类中,这是不需要我们处理的。但是使用Canvas制作菜单需要自己来处理焦点的移动,这里我们定义一个int类型变量selected,来记录焦点所在的菜单条目位置,也就是选择的索引。当用户按键的时候,我们在keyPressed()方法中判断用户的移动方向,对selected进行相关的加减运算,然后repaint()整个屏幕即可。 j氲皾? 7?QG焸$K? public void keyPressed(int keyCode){ 儓亭?2 桘[殛? //根据用户输入更新selected的值,并重新绘制屏幕 ‘6噡$J 柴耻簀9鱱? int action = this.getGameAction(keyCode); x???齮 崶??跷 switch(action){ 砓羓"? s?郑墄& case Canvas.FIRE: !浓1?X? 浭週f?W(? printLabel(selected); 088涮焂U? 詫Te_佶 break; O轗P)pd? b|梦壋絊 case Canvas.DOWN: 桄?囦梠 ?靂u箼4 selected = (selected+1)%4; [u赠耙Ge? 殂?蹼抻)4 break; E;?缉yㄣT 勥K>铿?? case Canvas.UP:{ ~/? 庴顯睴?}‘ if(--selected < 0){ X扤h籑C ‘<奇?維? selected+=4; ?撛嶩? 拔铅?W坆 } !2咍P#摡 頃:堚? break; ^_F=?厺? )U?矏? } 僺轷=\蓡 e螛xC簅3 default: ~"W經 :B ‘?鉩謄鰟? break; 戰P\q研 t`Vgr覮, } 岏淜J歔M? =c&┴D repaint(); B昕∽Iみ 蠱1综Rr袓? serviceRepaints(); #嘇??m D?踌o4? } 崴???輻 mj8YU.y艌? 这样我们就制作出了一个基本的菜单,你还可以发挥想象给被选中的菜单增加动画效果。MenuCanvas的代码如下所示: ズO??R 4ω^kR?? package com.j2medev.chapter3; S:鴠 € d?沙?H import javax.microedition.lcdui.*; 訬鬽 d=? N悷 莻? public class MenuCanvas extends Canvas{ 1牳歲缢frS @V讜}O惨O? //selected变量标记了焦点位置 腮)U?? o?lt;|+t厒 private int selected = 0; {S陓絽嗈3 瞴歌`? private int preferWidth = -1; H?yN剠蛑r W?&浪f private int preferHeight = -1; N+獺XP?_ 澭 x囂W?W public static final int[] OPTIONS = {0,1,2,3}; r媞斚? ~锴?I惔鷟 public static final String[] LABELS={"New Game","Setttings","High Scores","Exit"}; >Z踝礻b? <jK?稠(涝 public MenuCanvas() { `m~鐚磪G簅 vc*訥{? selected = OPTIONS[0]; 寽gO潇溁 O喍綂厠?Y //计算菜单选项的长度和高度值 D諽_m=b儫? 淃W?ys? Font f = Font.getDefaultFont(); @4?醹Y? ;砸?? for(int i = 0;i<LABELS.length;i++){ 愓[轞蹚^翳 o泦G宷瓊M? int temp = f.stringWidth(LABELS); K_qtと 鉋s99 囋 if(temp > preferWidth){ H??瑅償? Jkt?T)︻ preferWidth = temp; 洇瀶塂?龈 鰿?DU_b } oD?:6? ?d0辄涳q } 璤z腳对兝 E貹qE嚥A? preferWidth = preferWidth + 2*8; 韘疘9F.FY 琻璿Z屹 preferHeight = f.getHeight()+2*4; 揶L%?偑 ;竍?n } ~h旛?V? w挗Gb矑c? public void paint(Graphics g){ 掆揷2硻 哃結?Z? //清除屏幕 G?YI巛? )??lt;畾 ? int color = g.getColor(); 楽邖Q烚瑴? 袨骍幝 v? g.setColor(0xFFFFFF); 偮?LI t%k筜& g.fillRect(0,0,getWidth(),getHeight()); 搢Q嶺倆X? u幒i閹? g.setColor(color); 鍍N7):▲y? 坖@?勪N談 //计算整个菜单的高度,宽度和(x,y) |顸嶟m 5?烻8h‘ int rectWidth = preferWidth; 7唣鉀? 9?羺{ int rectHeight = preferHeight * LABELS.length; T?驫?? R狭窾? int x = (getWidth()-rectWidth)/2; |sz u郢氋Q 呮 瑧?\厣 int y = (getHeight()-rectHeight)/2; I术l忈y? 7b+?DB胰o //画矩形 t-?0c 輈3崠 g.drawRect(x,y,rectWidth,rectHeight); 堜JR-s[ =頰?? for(int i = 1;i<LABELS.length;i++){ O牦?? 蘋鱝$嘢? g.drawLine(x,y+preferHeight*i,x+rectWidth,y+preferHeight*i); i菮~?L=戈 w?5({ 9 } O慞菷?鮪? 灿éx霦 P //画菜单选项,并根据selected的值判断焦点 謖凾牝Wh爗 搨?訰,迍 for(int j = 0;j<LABELS.length;j++){ 葇訫脻^ N┲?籧 if(selected == j){ r絻?棄巨? A^7<G? ? g.setColor(0x6699cc); b?rE]? !?黿QS5 g.fillRect(x+1,y+j*preferHeight+1,rectWidth-1,preferHeight-1); S铺0儧? <褟縲滄(U? g.setColor(color); 祖?i湺?? I潄?p } 埡訥j-m鵒? l勓貎圓 g.drawString(LABELS[j],x+8,y+j*preferHeight+4,Graphics.LEFT|Graphics.TOP); 聞啺=u 醒? I?秮W? } %b嵩C[翓? g濈~甼步 } 9?獠姣? X?瓢?鷧 public void keyPressed(int keyCode){ 鷑筃k0@E陸 ,翁?鋁 //根据用户输入更新selected的值,并重新绘制屏幕 @}H?*埙ex 唴钻? int action = this.getGameAction(keyCode); =!` 庹`坸6/ switch(action){ 碋mc捀?_? 郜+2泍?? case Canvas.FIRE: 鶯?PU]丩& 亵劔j1蝞E printLabel(selected); 鉡瓵犸B? 驫? break; T衑 鼀5?\ 勇W賏*? case Canvas.DOWN: 袓? $_笍? ^?C>? selected = (selected+1)%4; 苔9ⅹo娽? nkgIA寎9 break; H`呱 zj? }禄Pv?? case Canvas.UP:{ 怒遣?1囙? j 搈?徱? if(--selected < 0){ 蕭2狆X笳? VX蠙?些1 selected+=4; nJjE?祉? 奭?|}獧 } 家? 啜f孚h淟W{ break; nf虚A叺5? V?懚|M=w } U?~?mD? ($洉影#=? default: 抃砥?汩帤 &%E‘y%jZ? break; 騢粉Dr韲 鈗L鏄 e\ } w6蟾陑 X粿A; c? repaint(); 峤?蟩怼 蜓蓔鸅P速 serviceRepaints(); 錔?lt;?Q /窶楟窀p } 殥/i*? 咅<"疫x酂? //showNotify()在paint()之前被调用 紙鰅?灊? 7Vl申]鞋‘Q public void showNotify(){ Ё叀聅爧^? ?=q靄 System.out.println("showNotify() is called"); □ 椆齪曁 27a 概銂y! } BG К=终 XY斅s菸 private void printLabel(int selected){ m业G 冖j@v?匌 System.out.println(LABELS[selected]); 忲k?罓=A? 6碝"t唅 } 弶ㄈ璜詂? 凲9n?W } |
|