J2ME简明教程分析

J2ME简明教程分析

第五章 MIDP低级界面开发——使用LCDUI低级API
高级API使用简单、有很高的可移植性,却无法控制许多细节。要对界面更多的进行控制,必须使用低级API。
5.1 Canvas类开发简介
低级界面屏幕都继承自名为Canvas的屏幕类。Canvas类提供了一系列键盘低级事件和绘图接口,具体的绘图操作则由一个名为Graphics的图形类来完成。
5.1.1 Canvas类简介
Canvas即画布,可以在其上绘制不同图案。Canvas提供了一个绘图接口方法paint(Graphics g),凡是继承Canvas的继承类都必须实现paint()方法,因此可以在paint方法中实现屏幕的绘画代码。
示例:
class MyCanvas extends Canvas
{
public void paint(Graphics g)
{

}
}
paint方法传入了Grpahics类型的参数g,具体的绘画将由Graphics的g实现。可以看出Canvas类和Graphics类的关系是画布与画笔的关系。
5.1.2 低级API与低级事件
Canvas可以处理低级事件,但并非处理所有的系统事件。设备支持哪些系统事件,必须由硬件的支持程度来判断。Canvas提供一些方法判断硬件支持程度。
功能
检测方法
低级事件/回调函数
键盘事件
支持
keyPressed(int keycode)
keyReleased(int keycode)
屏幕事件
支持
showNotity()
hideNotify()
重绘事件
支持
paint(Graphics g)
是否支持双缓冲
Canvas.isDoubleBuffered()

是否支持repeat
Canvas.hasRepeatdEvent()
keyRepeated(int keycode)
是否支持触控屏幕事件
Canvas.hasPointerEvents()
pointerPressed(int x, int y)
pointerReleased(int x, int y)
是否支持触控屏幕拖拽事件
Canvas.hasPointerMotionEvnets()
pointerDragged(int x, int y)
机器一定会支持的键盘事件有keyPressed()、keyReleased(),屏幕事件showNotify()、hideNotidy(),以及重绘事件paint()。
注意:除了showNotidy()之外,其它回调函数只有在此Canvas是目前屏幕上的画面时才会被调用。
5.1.3 重绘事件
示例:
//CanvasTestMidlet.java
import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;
public class CanvasTestMidlet extends MIDlet
{
private Display display;
public CanvasTestMidlet()
{
display = Display.getDisplay(this);
}
public void startApp()
{
MyCanvas mc = new MyCanvas();
display.setCurrent(mc);
}
public void pauseApp()
{
}
public void destroyApp(boolean unconditional)
{
}
}
//MyCanvas.java
import javax.microedition.lcdui.*;
public class MyCanvas extends Canvas
{
/** Creates a new instance of MyCanvas */
public MyCanvas()
{
}
public void paint(Graphics g)
{
}
}
任何时候都可以自行调用repaint()产生重绘事件。repaint()有两个同名方法,其中一个需要四个参数,用来指定重画区域的X、Y坐标,宽度与高度;另外一个无参数,代表重绘整个屏幕。调用repaint()之后会立刻返回,继续下面工作,调用paint()回调函数的工作则由一个专门处理UI的线程来完成。若希望等到paint()完成后再返回,可以在repaint()之后立刻调用serviceRepaints()方法。
注意:serviceRepaints()用来强制队列中的重绘事件快点做完,如果队列中没有重绘事件,则serviceRepaints()什么也不会做,因此在调用serviceRepaints()之前,通常伴随一个repaint()。
5.1.4 坐标系统
在使用绘图函式前,请先注意MIDP 中X 坐标与Y 坐标的定义方式。传统的笛卡尔坐标其原点在左下角,向右X 坐标值递增,向上Y坐标值递增。
但是我们在手机的屏幕上做图时,变成向右X 坐标值递增,向下Y 坐标值递增。
5.1.5 像素(Pixel)
我们在所有图形相关函数之中所使用的坐标所代表的并非像素本身,而是指像素和像素之间的空格所构成的坐标,如下图所示:
像素与像素之间所构成的坐标
所以一般我们所说的坐标(3,1)并非指位于(3,1)这个像素,而是指像素(2,0)、(2,1)、(3,0)、(3,1)所包围的这个部分。也正因为坐标指的并非图素本身,所以会造成在绘制图型和填满区块时有所差异,这两者的不同我们将在以后说明。
5.1.6 Graphics入门
paint(Graphics g)方法会传入一个Graphics对象作为参数,可以把该对象当作是一个抽象的画笔,调用Graphics的方法,就可以在这个画布上绘图。
编写我们自己的Canvas时,要做的第一件事就是把画面清空,然后才开始绘图,避免画面上残留前一个画面所遗留下的东西。
//清屏
public void paint(Graphics g)
{
g.setColor(255, 0, 255);
g.fillRect(0, 0, getWidth(), getHeight());
… …
}
上述范例中,我们使用Graphics的setColor()来设置画笔颜色:
setColor(int r, int g, int b)注意,rgb的值限定在0~255之间。
或setColor(int rgb) 直接传入0x00RRGGBB这样的整数。
设定好颜色后,可以使用getRedComponent()、getGreenComponent()、getBlueComponent()分别取得R、G、B的颜色设定。或者直接使用getColor()取得0x00RRGGBB这样的整数,也就是说,最后第0~7 位代表蓝色、8~15 代表蓝色,16~23 代表红色。
getDisplayColor()较特殊,返回机器上绘图时真正使用的颜色。有些机器不具有显示所有颜色的能力。屏幕的灰度数可以用getGrayScale()取得,也可以用setGrayScale(),灰度数取值在0~255之间。使用这个函式的时候请特别注意,如果您已经使用了相对应的setGrayScale()来设定灰阶色阶数,那么getGrayScale()函式只是单纯地传回设定值。但是如果您没有设定灰阶色阶数,那么呼叫getGrayScale()函式的时候,会导致系统利用目前作用色的R、G、B 值来做大量运算,并求得最接近的灰阶色阶数。
5.1.7 绘制直线
我们可以使用Graphics 类别的drawLine()函式绘制线段。DrawLine 的四个参数分别是起点X 坐标,起点Y 坐标、终点X 坐标、终点Y 坐标。举例来说,如果我们函式呼叫为:g.drawLine(1,1,1,6)
则实际绘制的线段如下图所示:
实际绘制出来的线段的位置
我们可以发现坐标右边的相素都会被填满。
如果我们函式调用为:
g.drawLine(1,1,6,1)
则实际绘制的线段如下图所示:
实际绘制出来的线段的位置
我们可以发现坐标下方的像素都会被填满。
当我们绘图形时,有所谓的笔触(stroke style)。Graphics提供两种笔触,分别是Graphics.SOLID和Graphics.DOTTED:
g.setStrokeStyle(Graphics.DOTTED);
相应的取得目前所用笔触:g.getStrockStyle()
5.1.8 画弧形
我们可以使用Graphics 类的drawArc()方法绘制弧形。drawArc 共有6 个参数,它们分别是:前四个决定弧形所在的矩形范围,第五个决定起始角度,第六个参数则决定弧形本身所涵盖的角度。
如果我们方法调用为:
g.drawArc(20,10,width,height,45,90);
则实际绘制的弧形如下图所示:
实际绘制出来的弧形
填充弧形
我们可以使用Graphics 类别的fillArc()函式填充弧形。fillArc 共有6 个参数,它们分别是:前四个决定弧形所在的矩形范围,第五个决定起始角度,第六个参数则决定弧形本身所涵盖的角度。
如果我们方法调用为:
g.fillArc(20,15,width,height,45,90);
则实际绘制的填充弧形如下图所示:
实际绘制出来的填充弧形
5.1.9 矩形
画矩形:我们可以使用Graphics 类别的drawRect()函式绘制矩形。drawRect 有4 个参数,分别是起点X 坐标、起点Y 坐标、宽度、长度。
如果我们函数调用为:
g.drawRect(1,1,6,8)
则实际绘制的矩形如下图所示:
实际绘制出来的矩形
我们可以发现所构成的矩形路径,其右边和下方的像素都被填满了。
画圆角矩形:我们可以使用Graphics 类别的drawRoundRect()函式绘制圆角矩形。其实drawRoundRect()和drawRect()函式的前四个参数意义相同,唯一的差距只有在最后两个参数,它们分别是圆角所在矩形的宽度,以及圆角所在矩形的高度。
如果我们方法调用为:
g.drawRoundRect(1,1,6,8,arcWidth,arcHeight)
则实际绘制的圆角矩形,在矩形的部分和使用drawRect()的结果相同,差别只有在四个直角的样子不再是直角,而变成圆角。
如下图所示:
实际绘制出来的圆角矩形
填充矩形:我们可以使用Graphics 类别的fillRect()函式填充矩形。fillRect 有4 个参数,分别是起点X 坐标、起点Y 坐标、宽度、长度。
如果我们方法调用为:
g.fillRect(1,1,6,8)
则实际绘制的矩形如下图所示:
实际绘制出来的填充矩形
我们可以发现只有包含在矩形路经之内的图素才会被填满,这和drawRect()函式的结果有所不同(上下都差一个图素的大小)。
填充圆角矩形:我们可以使用Graphics 类别的fillRoundRect()函式填充圆角矩形。其实fillRoundRect()和fillRect()函式的前四个参数意义相同,唯一的差距只有在最后两个参数,它们分别是圆角所在举行的宽度,以及圆角所在矩形的高度。
如果我们方法调用为:
g.fillRoundRect(1,1,6,8,arcWidth,arcHeight)
则实际绘制的圆角矩形,在矩形的部分和使用fillRect()的结果相同,差别只有在四个角的样子不再是直角,而变成圆角,如下图所示:
实际绘制出来的填充圆角矩形
5.1.10 三角形
绘制三角形,使用三个顶点,分别画线即可,因此MIDP只提供填充三角形的功能:
g.fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) ;
练习:尝试自己绘制三角形,并填充它
5.2 Canvas与屏幕事件处理
Canvas本身具有两种状态: