下面给出一段代码,让大家体会一下如何在实际开发过程当中妥善处理屏幕事件:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class test4 extends Canvas
implements CommandListener
{
public test4()
{
setTitle("全屏幕测试") ;
setTicker(new Ticker("Ticker ")) ;
addCommand(new Command("全屏幕",Command.SCREEN,1)) ;
addCommand(new Command("正常",Command.SCREEN,1)) ;
setCommandListener(this) ;
}
public void paint(Graphics g)
{
g.setColor(125,125,125);//灰色
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(0,0,0);//黑色
g.drawLine(10,10,150,10);
}
public void commandAction(Command c,Displayable s)
{
String cmd = c.getLabel();
if(cmd.equals("全屏幕"))
{
setFullScreenMode(true) ;
}else if(cmd.equals("正常"))
{
setFullScreenMode(false) ;
}
}
protected void sizeChanged(int w,int h)
{
System.out.println("改变后的宽度:"+w) ;
System.out.println("改变后的高度:"+h) ;
}
protected void hideNotify()
{
System.out.println("屏幕被系统遮蔽") ;//会在WTK控制台中显示,
//读者需要注意
}
protected void showNotify()
{
System.out.println("屏幕显示在屏幕上") ;
}
}
从截图1和截图3可以看出全屏幕和普通模式的区别,全屏幕的Canvas的显示区域覆盖了原来显示标题和Ticker的地方。
4.4 键盘及触控屏幕事件的处理
如果我们需要在Canvas里处理我们的按键事件,我们必须覆写 Canvas的keyPressed(),keyReleased()和keyReapeated()这三个方法,其中keyReapeated()方法JTWI并未做硬性规定,所以我们在开发的时候一定要用Canvas.hasRepeatedEvents()方法来进行实际的侦测,当按下按键时会触发keyPressed()方法,松开时会引发keyReleased()方法 ,长时间按住的话则会引发keyRepeated()方法,JTWI硬性规定MIDP2.0的目标设备必须硬性支持ITU-T的电话键盘,即必须使数字0到9,“*”,“#”必须能在 Canvas中得到定义,当然我们也可以扩充其他按键,但是这样对程序的移植就会有影响,下面我们通过代码来看看如何在实际开发中运用上面提到的三个方法。
按下前:
按下后:
代码:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class test5 extends Canvas
implements CommandListener
{
public test5()
{
addCommand(new Command("测试",Command.SCREEN,1)) ;
setCommandListener(this);
}
boolean pressed = false ;
public void paint(Graphics g)
{
g.setColor(125,125,125);
g.fillRect(0,0,getWidth(),getHeight());
if(pressed)
{
g.setColor(0,0,0);
g.drawLine(20,20,120,20);
g.drawLine(20,20,20,100);
g.setColor(255,255,255);
g.drawLine(120,20,120,100);
g.drawLine(20,100,120,100);
}else
{
g.setColor(255,255,255);
g.drawLine(20,20,120,20);
g.drawLine(20,20,20,100);
g.setColor(0,0,0);
g.drawLine(120,20,120,100);
g.drawLine(20,100,120,100);
}
}
public void commandAction(Command c,Displayable s)
{
System.out.println("Command Action");
}
protected void keyPressed(int keycode)
{
System.out.println("Key Pressed");
pressed = true ;
repaint() ;
}
protected void keyReleased(int keycode)
{
System.out.println("Key Released");
pressed = false ;
repaint() ;
}
}
对于触控事件(pointer events)的方法,应用程序可以通过覆写pointerPressed(),pointerReleased()和pointerDragged方法,(分别对应于手写笔的按下,松开,拖拽三个动作)其处理过程和按键处理几乎一致,所以这里不螯述。
4.5 Graphics相关类
在这一节里面我们通过设计一个稍微复杂一点的动画来体现Graphics在实际开发当中带来的便利,在这里给出几段曾经对我们启发很大的代码,通过围绕这几段代码进行分析,来掌握Graphics在实际开发当中的作用。
4.5.1 Image类
前面我们谈到了双缓冲区问题,我们先就Image这个类来谈一谈。
在介绍Image之前,先介绍几个比较基础的概念,无论是图像还是文字在Graphics中都是通过锚点(anchor points)来控制它们具体的方位,对于Image而言有如下几个锚点常量:LEFT,RIGHT,HECENTER,TOP,VCENTER,BOTTOM, BASELINE。其具体位置对应如下:
Image分为可变和不可变两种类型的,不可变的Image是从资源文件,二进制数据,RGB数值,及其他Image直接创建的,一旦创建完成,Image就无法再变化。不可变的Image通过Image.createImage(String name) 方法从指定的路径中读取需要创建Image所必须的数据,注意参数中的字符串必须以“/”打头,并且包括完整的名称。
可变的Image以给定的大小创建,它是可以修改的,可变的Image由Image.createImage(int width,int height)方法来创建,需要给定长宽,Image的其他显示特性和机器的显示屏完全一致。
我们前面提到了撕裂现象,它产生的原因是因为显示屏在显示图像前都会先参照影象内存,然后当绘制速度慢到一定程度时,显示在屏幕上的画面会由前一帧画面的一部分和后一帧画面的一部分组成,这样造成图像“撕裂”,为了解决这个问题,手机厂商可以从硬件上支持DoubleBuffer,即双缓冲区,这样显示屏绘图的时候都可以使用一个影象内存来绘图,另一个影象内存来进行程序绘图,这样交叉进行,可以避免画面撕裂的产生。
如果硬件厂商并未在硬件上支持DoubleBuffer怎么办呢?我们可以从程序上着手,自己设计一个双缓冲区。
代码片段如下:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class test6 extends Canvas
implements Runnable,CommandListener
{
Command start = new Command("开始",Command.OK,1) ;
Command stop = new Command("停止",Command.STOP,1) ;
private Image offscreen ;
public test6)
{
addCommand(start);
setCommandListener(this) ;
if(isDoubleBuffered())
{
System.out.println("支持双缓冲区");
}else
{
System.out.println("不支持双缓冲区,启动自制双缓冲区");
offscreen = Image.createImage(getWidth(),getHeight());
}
}
public void paint(Graphics g)
{
if(isDoubleBuffered())
{
System.out.println("On-Screen绘图");
clear(g);
paintAnimation(g,100,10,r) ;
paintCross(g,x,y,length) ;
}else
{
System.out.println("Off-Screen绘图");
Graphics offg = offscreen.getGraphics() ;
clear(offg) ;
paintAnimation(offg,100,10,r) ;
paintCross(offg,x,y,length) ;
g.drawImage(offscreen,0,0,0);
}
}
public void clear(Graphics g)
{
//把屏幕清成白色
g.setColor(255,255,255);
g.fillRect(0,0,getWidth(),getHeight());
}
int r = 0 ;
public void paintAnimation(Graphics g,int x,int y,int l)
{
g.setColor(0,0,0);
g.drawRect(x,y,l,l);
}
int x =50 ;
int y =50 ;
int length = 5 ;
public void paintCross(Graphics g,int x,int y,int length)
{
g.setColor(255,0,0);
g.drawLine(x-length,y,x+length,y);
g.drawLine(x,y-length,x,y+length);
}
boolean conti = false ;
public void commandAction(Command c,Displayable s)
{
String cmd = c.getLabel() ;
if(cmd.equals("停止"))
{
conti = false ;
removeCommand(stop);
addCommand(start) ;
}else if(cmd.equals("开始"))
{
removeCommand(start);
addCommand(stop) ;
conti = true ;
Thread t = new Thread(this);
t.start();
}
}
int rate = 50 ; //每1/20秒画一次
public void run()
{
long s = 0 ;
long e = 0 ;
long diff = 0 ;
while(conti)
{
s = System.currentTimeMillis() ;
r++;
if (r > 10)
r = 0;
repaint();
serviceRepaints() ;
e = System.currentTimeMillis() ;
diff = e-s ;
if(diff<rate)
{
try
{
Thread.sleep(rate-diff);
}catch(Exception exc){}
}
}
}
protected void keyPressed(int keycode)
{
switch(getGameAction(keycode))
{
case Canvas.UP :
y = y-2 ;
break ;
case Canvas.DOWN :
y = y+2 ;
break ;
case Canvas.LEFT :
x = x-2 ;
break ;
case Canvas.RIGHT :
x = x+2 ;
break ;
}
repaint();
}
}
需要提醒各位读者注意的是Image.createImage()非常浪费内存,我们最好能够尽量重复使用它。
4.5.2 字体类
Graphics中还提供了对了对字体的控制方法,每个Graphics都有一个Font对象与其关联,来进行文字的渲染操作,调用其类方法setFont(null),即可使字体恢复到默认状态,对于具体的参数,Font提供了以下常量,来控制Font的属性:
字体大小:SMALL、MEDIUM、LARGE
字体外观:PROPORTIONAL、MONOSPACE、SYSTEM
字体风格:PLAIN、BOLD、ITALIC、UNDERLINED
通过charWidht(),charsWidth(),stringWidth(),substringWidth()来获得字符串,字符,字符集合的宽度,垂直方面则可以参考getHeight()和getBaselinePosition()方法获得。
当你不对Font进行设定时,机器会自动从设备中选择最合适的 Font属性。
评论