我们从javax.microedition.lcdui.Canvas开始了解我们的低级UI,我们要用到低级UI必须要继承Canvas这个抽象类,在 Canvas的核心是paint()这个方法,这个方法做是负责绘制屏幕上的画面,每当屏幕需要重新绘制时,就会产生重绘事件时,系统就会自动调用paint(),并传入一个Graphics对象。
任何时候我们都可以通过调用reapaint()方法来产生重绘事件,它有两个方法,一个需要四个参数,分别用来指示起始坐标(X,Y),长宽,另一个则不需要任何参数,代表整个画面重新绘制。
我们可以通过getWidth()和getHeight() 方法获得Canvas的当前范围大小。每当Canvas 范围大小发生变化时,就会自动调用Canvas类的 sizeChanged()方法。
在低级UI里,我们可以直接把Graphics渲染到屏幕上,也可以在屏幕外合成到一个 Image中,已渲染的图形具体是合成Image还是显示到屏幕上,要看这个Graphics具体的来源而定,而渲染到屏幕上的Graphics对象将被送到paint()方法中来进行调度,这也是显示在屏幕上的唯一的途径,仅在paint()方法的执行期间这个应用程序可以对Graphics进行操作,至于要渲染到Image中的Graphics对象,当需要调用它的时候,可以通过Image.getGraphics()方法来取得相应的Graphics,它将可以被应用程序一直占有,在paint()方法运作的任何时候渲染到屏幕上,这也为我们在对不支持DoubleBuffered的手机开发提供了一些思路,可以通过Image来自行设计双缓冲区,避免图像出现所谓的撕裂现象。
4.1 低级API与低级事件的联系
与高级UI相比,低级UI就自由很多,任何时候我们可以调用repaint()产生重绘事件,调用完了repaint()会立刻返回,调用paint()回调函数则是由另一个专门的线程来完成。
底层事件大致可分为三类:Press Events(按键事件),Action Keys(动作按键,PointerEvents(触控事件)。
本节我们将围绕这三个主题来介绍一下这种事件的用法:
按键事件的几个核心方法为:keyPressed(),keyReleased(),keyRepeated(),当按键按下时会触发keyPressed(),当松开按键时,会触发keyReleased(),当长时间按住按键时会触发keyRepeated(),但是RepeatEvents不是JTWI要求强制支持的,所以使用之前要进行测试,看设备是否支持。在Canvas里面我们每按下一个按键都会触发keyPressed()函数,并传入相应位置的整数值,我们在MIDP规范中可以很容易的发现,KEY_NUM0——KEY——NUM9十个常数分别代表键盘上的0-9,还有两个功能键,KEY_STAR,KEY_POUND,如果我们传入的值小于0,代表我们传入了不合法的keycode,某些机器上还支持连续按键响应,但这并不是JTWI规定要支持的,所以我们在进行实际开发之前一定要用我们前面讲到的hasRepeatEvents()方法来进行判定。
动作按键主要针对游戏来设计的,在API中定义了一系列的动作事件:UP,DOWN,LEFT,RIGHT,GAME_A,GAME_B,GAME_C,GAME_D,当按下这些按键时会映射到我们自己为每个按键事件编写的方法,来完成一些动作。不过我们在MIDP2.0里我们已经有专门的游戏开发包了,所以我在这里就不重点介绍了。
触控事件主要面向高端设备,并非JTWI要求强制支持的,其核心方法为:pointerPressed(),pointerReleased(),pointerDragged(),分别对应我们通常所用的移动设备手写笔的点,击,拖拽几个动作,我们在这三个方法里可以定义相应的事件处理函数。在索爱P910C这样的高端手机上,支持屏幕的触控事件,我们在屏幕上点击,可以引发pointerPressed()函数,并传入当时位置的坐标,放开后,会引发pointerReleased()函数,同样也会传入坐标,具体的使用方法和keyPressed()以及keyReleased()大同小异,在后面的章节将会有对键盘及触控屏幕事件的详细叙述,同时大家可以参考一下WTK的说明文档获得比较详细的方法使用规则
4.2 重绘事件及Graphics入门
4.2.1 坐标概念
我们在MIDP程序设计中用到的坐标系和一般我们平时用到的坐标系不一样,可见下图:
这是我们在绘制图象时要注意的。
下面我们来讲一讲Graphics这个对象,我们可以把它当作一个白纸,只要调用这个方法,我们就可以运用自己的想象力在这张白纸上画出自己想要的图案。
4.2.2 颜色操作
我们可以在WTK的控制台看到下面这个程序运行以后显示其Canvas的RGB值和灰度等参数,读者可以运行下面这个程序来获得对Graphics这个对象的初步了解。
下面我用一段简单的代码来说明一下这个Graphics对象的应用:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class test extends Canvas
{
public void paint(Graphics g)
{
g.setColor(255,255,0);
g.fillRect(0,0,getWidth(),getHeight());
int c=g.getColor();
int dc=g.getDisplayColor(g.getColor());
System.out.println("当前画面的颜色为:"+Integer.toHexString(c));
System.out.println("当前画面的R值为:"+g.getRedComponent());
System.out.println("当前画面的G值为:"+g.getGreenComponent());
System.out.println("当前画面的B值为:"+g.getBlueComponent());
System.out.println("当前画面的显示颜色为:"+Integer.toHexString(dc));
System.out.println("当前画面的灰度为:"+g.getGrayScale());
}
}
需要大家注意的是R,G,B的值只能在0——255之间,不可以超出这个范围,另外我们可以直接用0x00RRGGBB格式进行颜色的调配。
4.2.3 绘图操作
Graphics类提供的大量的绘图操作,这里给出了相关操作的方法列表供读者参考:
void |
drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) Draws the outline of a circular or elliptical arc covering the specified rectangle, using the current color and stroke style. |
void |
drawChar(char character, int x, int y, int anchor) Draws the specified character using the current font and color. |
void |
drawChars(char[] data, int offset, int length, int x, int y, int anchor) Draws the specified characters using the current font and color. |
void |
drawImage(Image img, int x, int y, int anchor) Draws the specified image by using the anchor point. |
void |
drawLine(int x1, int y1, int x2, int y2) Draws a line between the coordinates (x1,y1) and (x2,y2) using the current color and stroke style. |
void |
drawRect(int x, int y, int width, int height) Draws the outline of the specified rectangle using the current color and stroke style. |
void |
drawRegion(Image src, int x_src, int y_src, int width, int height, int transform, int x_dest, int y_dest, int anchor) Copies a region of the specified source image to a location within the destination, possibly transforming (rotating and reflecting) the image data using the chosen transform function. |
void |
drawRGB(int[] rgbData, int offset, int scanlength, int x, int y, int width, int height, boolean processAlpha) Renders a series of device-independent RGB+transparency values in a specified region. |
void |
drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) Draws the outline of the specified rounded corner rectangle using the current color and stroke style. |
void |
drawString(String str, int x, int y, int anchor) Draws the specified String using the current font and color. |
void |
drawSubstring(String str, int offset, int len, int x, int y, int anchor) Draws the specified String using the current font and color. |
void |
fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) Fills a circular or elliptical arc covering the specified rectangle. |
void |
fillRect(int x, int y, int width, int height) Fills the specified rectangle with the current color. |
void |
fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) Fills the specified rounded corner rectangle with the current color. |
void |
fillTriangle(int x1, int y1, int x2, int y2, int x3, int y3) Fills the specified triangle will the current color. |
主要是一组和绘画和填充的方法。请参考API的查看更多细节。
下面我们就来谈一谈如何用Graphics中线形的概念。如果我们需要绘制一条直线,我们可以调用drawLine()方法,需要定义其开始坐标和结束坐标,共四个参数,同时,Graphics提供两种形式的线条,一个是虚线,即Graphics.DOTTED,一个是实线,即Graphics.SOLID。
同样我们给出一段代码供大家参考:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class test2 extends Canvas
{
public void paint(Graphics g)
{
g.setColor(255,255,255);
g.fillRect(0,0,getWidth(),getHeight());
//在以后的实际开发当中会经常用到上面两行代码,它们的作用是进行画面的初
//化
g.setColor(255,0,0);
g.drawLine(1,1,100,10);
g.setStrokeStyle(Graphics.DOTTED); //虚线
g.setColor(125,125,125);
g.drawLine(10,10,100,100);
g.setStrokeStyle(Graphics.SOLID); //实线
}
}
用类似的方法,我们可以实现用Graphics的drawRect()和drawRoundRect()方法来绘制矩形和圆角矩形,我们也给出一段代码,让大家仔细观察一下两种矩形的区别:
import javax.microedition.lcdui.*;
import javax.microedition.midlet.*;
public class test3 RectTestCanvas extends Canvas
{
public void paint(Graphics g)
{
clear(g) ;
g.setColor(255,0,0) ;
g.drawRect(5,5,100,20);
g.setColor(0,255,0) ;
g.fillRect(5,30,100,20);//fillRect()和drawRect()方法的区别在于一个填充
//一个不填充
g.setColor(0,0,255) ;
g.drawRoundRect(5,55,100,20,20,20);
g.setColor(255,0,255) ;
g.fillRoundRect(5,80,100,20,20,20);
}
public void clear(Graphics g)
{
//把屏幕清成白色
g.setColor(255,255,255);
g.fillRect(0,0,getWidth(),getHeight());
}
}
}
4.3 Canvas与屏幕事件处理
Canvas本身有两种状态,一种是普通默认情况下的,一种是全屏状态,可以用setFullScreenMode()方法来对其设定,两者之间的区别在于当我们使用全屏幕状态的时候,Title、Ticker以及我们的Command都无法在屏幕上显示。
当我们调用setFullScreenMode()的时候,不管是什么模式,都会调用seizeChanged()这个方法,并传入屏幕的高度和宽度作为其参数。
对于某些突发事件,比如说来电等等,屏幕会被系统画面所覆盖的时候,就会调用hideNotify()这个方法,当恢复原状时,就会调用我们原本的画面,那么系统就会同时调用showNotify()这个方法。在实际操作过程当中,应该覆写这两个方法,以便在可见性变化时,使程序做出相应的反应,Canvas会在它被显示的时候自动调用paint()方法,所以我们不必去调用repaint()方法。
评论