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本身具有两种状态: