资源描述
v 第4章学习了高级用户界面及事件处理,可以看到MIDP本身提供了大量的控件开发类。使用这些控件开发大大减少了开发的时间和工作量。 v 但是只能使用已有的模式来开发。如果想构造自己的屏幕类或者组件,就要使用低级用户界面来开发。这样开发人员就可以获得完全的界面控制能力。这在游戏的开发中是非常重要的。 v Canvas Canvas简介简介5.1低级事件的处理低级事件的处理5.2 Graphics Graphics 开发简介开发简介5.3 MIDP Timer API MIDP Timer API5.4综合实例:编写欢迎界面综合实例:编写欢迎界面5.5小结小结5.65.1 Canvas简介v 正如高级界面屏幕类都继承Screen类一样,我们要用到低级用户界面必须要继承Canvas 这个抽象类,Canvas是Displayable的直接子类,属于J2ME中的低级API。 v 用户利用这些低级API可对设备精确控制,如绘制像素、接收原始的用户输入事件等。 v 与高级API相比控制更加灵活,但这是以其复杂性、高成本为代价的,并牺牲了一定的可移植性。它的基本用法与其他Displayable对象一致。 v Canvas 的核心是paint()这个方法,这个方法做是负责绘制屏幕上的画面,每当屏幕需要重新绘制时,就会产生重绘事件,系统就会自动调用paint(),并传入一个Graphics 对象。 v 因此继承Canvas类的程序结构如下:vclass MyCanvas extends Canvasv v protected void paint(Graphics g)v v v v 任何时候都可以通过调用reapaint()方法来产生重绘事件,它有两个方法,一共需要四个参数,分别用来指示起始坐标(X, Y)和长宽,另一个则不需要任何参数,代表整个画面重新绘制。 v 可以通过getWidth()和getHeight() 方法获得Canvas 的当前范围大小。每当Canvas 范围大小发生变化时,就会自动调用Canvas 类的 sizeChanged()方法。 v 在低级UI 里,我们可以直接把Graphics 渲染到屏幕上,也可以在屏幕外把Graphics合成到一个 Image中。 v 已渲染的图形具体是合成Image 还是显示到屏幕上,要由这个Graphics 具体的来源而定,而渲染到屏幕上的Graphics 对象将被送到paint()方法中来进行调度,这也是图形显示在屏幕上的唯一的途径。 v 只有在paint()方法的执行期间这个应用程序才可以对Graphics 进行操作,至于要渲染到Image 中的Graphics 对象,当需要调用它的时候,可以通过Image.getGraphics()方法来取得相应的Graphics,它将可以被应用程序一直占有。 v 在paint()方法运作的任何时候渲染到屏幕上,这也为开发不支持DoubleBuffered 的手机提供了一些思路,可以通过Image 来自行设计双缓冲区,避免图像出现所谓的撕裂现象。 v 我们还可以通过下面的两种方法获取Canvas对象的大小:v public int getHeight(); /获取可显示区域的高度(以像素为单位)v public int getWidth(); /获取可显示区域的宽度(以像素为单位)5.2 低级事件的处理v 与高级UI 相比,低级UI 就自由很多,任何时候都可以调用repaint()产生重绘事件,调用完repaint()会立刻返回,调用paint()回调方法则是由另一个专门的线程来完成。 v 底层事件大致可分为:Press Events(按键事件),PointerEvents(触控事件)。本节将围绕这两个主题来介绍一下这种事件的用法。 5.2.1 按键事件v 使用Canvas类的一个好处是可以获得键盘输入的按键代码,按键事件的几个核心方法是。 v keyPressed()、keyReleased()、keyRepeated(),当按键按下时会触发keyPressed(),当松开按键时,会触发keyReleased(),当长时间按住按键时会触发keyRepeated(),但是RepeatEvents 不是JTWI 要求强制支持的,所以使用之前要进行测试,看设备是否支持。 v 在Canvas 里面每按下一个按键都会触发keyPressed()方法,并传入相应位置的整数值,我们在MIDP 规范中可以很容易发现,KEY_NUM0KEY_NUM9十个常数分别代表键盘上的09。 v 还有两个功能键,KEY_STAR,KEY_POUND,如果我们传入的值小于0,代表我们传入了不合法的keyCode,某些设备上还支持连续按键响应,但这并不是JTWI 规定要支持的,所以我们在进行实际开发之前一定要用前面讲到的hasRepeatEvents()方法来进行判定。 v 一般来说在继承Canvas的类中只要重载这三个方法就可以了。当按键被按下的时候,按键的代码会自动的传给这三个方法。 v 动作按键主要针对游戏来设计的,在API 中定义了一系列的动作事件:UP、DOWN、LEFT、RIGHT和FIRE,分别代表上、下、左、右和Select键。 v 但这些按键需要通过getGameAction方法进行处理键盘代码。当按下这些按键时会映射到我们为每个按键事件编写的方法,来完成一些动作。 图图5-1 按键按下前按键按下前 图图5-2 5-2 按键按下后按键按下后 5.2.2 触控事件v 现在很多手机支持触摸屏的输入,触控事件主要面向高端设备,并非JTWI 要求强制支持的,Canvas提供了以下三个方法获得当前触摸点的坐标。 (1)pointerPressed (int x, int y) (2)pointerReleased (int x, int y) (3)pointerDragged (int x, int y) v 分别对应通常所用的移动设备手写笔的按下、松开和拖曳几个动作,在这三个方法里可以定义相应的事件处理方法。 v 在索爱P910C这样的高端手机上,支持屏幕的触控事件:在屏幕上按下手写笔,可以触发pointerPressed()方法,并传入当时位置的坐标。 v 放开后,会触发pointerReleased()方法,同样也会传入坐标,对于触控事件(pointer events)的方法,应用程序可以通过覆盖pointerPressed()、pointerReleased()和pointerDragged 方法,(分别对应于手写笔的按下和松开、拖曳三个动作)其处理过程和按键处理基本一致。 5.2.3 Canvas 与屏幕事件处理v Canvas 本身有两种状态,一种是普通默认情况下的,一种是全屏状态,可以用setFullScreenMode()方法来对其设定。 v 两者之间的区别是当处于全屏状态的时候,Title、Ticker 和Command 都无法在屏幕上显示。 v 当调用setFullScreenMode()的时候,不管是什么模式,都会调用seizeChanged()这个方法,并传入屏幕的高度和宽度作为其参数。 v 对于某些突发事件,如说来电等,屏幕会被系统画面所覆盖的时候,就会调用hideNotify()这个方法,当恢复原状时,就会调用原来的画面,那么系统就会同时调用showNotify()这个方法。 v 在实际操作过程当中,应该覆盖这两个方法,以便在可见性变化时,使程序做出相应的反应,Canvas 会在它被显示的时候自动调用paint()方法,所以不必去调用repaint()方法。 图图5-3 5-3 全屏幕测试全屏幕测试5.3 Graphics 开发简介v 前面的章节里我们学习了Canavs类,它提供了一个绘图接口方法paint(Graphics g),具体的绘图由参数g来实现。 v 由此可以看出Canvas类和Graphics类的关系就是画布和画笔的关系。我们使用Graphics类可以在屏幕上绘制图片、线条、文字等多种低级别的界面来。我们编写的游戏程序也都要用到Graphics类。 5.3.1 坐标概念v 在MIDP 程序设计中用到的坐标系和平时用到的坐标系不一样,如图5-4所示。 图图5-4 5-4 坐标坐标 v Graphics类绘画手机中的原点并不是位于屏幕的最上端的,由于手机屏幕包括了多个区域,如标题区域、内容区域和按钮区域等。实际原点位于内容区域的左上角。 v 下面我们来讲一讲Graphics 这个对象,我们可以把它当作一个白纸,只要调用这个方法,我们就可以运用自己的想象力在这张白纸上画出自己想要的图案。 5.3.2 绘制基本图形v Graphics 类提供的大量的绘图操作,这里给出了相关操作的方法供读者参考。 v 绘制直线:v void drawLine(int x1, int y1, int x2, int y2)v 绘制弧线:v void drawArc(int x, int y, int width, int height, int startAngle,int arcAngle) v 绘制图片:v void drawImage(Image img, int x, int y, int anchor)v 绘制矩形:v void drawRect(int x, int y, int width, int height) v 绘制圆角矩形:v void drawRoundRect(int x, int y, int width, int height, int arcWidth,vint arcHeight) v 绘制字符串:v void drawString(String str, int x, int y, int anchor)v 绘制填充矩形:v void fillRect(int x, int y, int width, int height) 图图5-5 5-5 绘制的直线、矩形和填充矩形绘制的直线、矩形和填充矩形 5.3.3 颜色操作v Graphics类提供了3个设置颜色的方法。 (1)public void setColor(int red, int green, int blue) (2)public void setColor(int RGB) (3)public void setColor(int value) v 需要大家注意的是,red、green和blue 的值只能在0255 之间,不可以超出这个范围。 v 可以在WTK 的控制台看到下面这个程序运行以后显示其Canvas 的RGB 值和灰度等参数如图5-6所示,读者可以运行下面这个程序来获得对Graphics 这个对象的初步了解。 图图5-6 5-6 颜色的操作颜色的操作 5.3.4 锚点(anchor points)v 通过锚点(anchor points)来控制它们具体的方位,锚点的作用就是设置占用屏幕矩形方块的具体位置。有如下几个锚点常量。 (1)static int TOP:将Text对象和Image对象的锚点定位于对象顶部的常数。 (2)static int BASELINE:将Text对象和Image对象的锚点定位于对象基准线的常数。 (3)static int BOTTOM:将Text对象和Image对象的锚点定位于对象底部的常数。 (4)static int LEFT:将Text对象和Image对象的锚点定位于对象左边的常数。 (5)static int HCENTER:将Text对象和Image对象的锚点定位于对象水平居中的常数。 (6)static int VCENTER:将Text对象和Image对象的锚点定位于对象垂直居中的常数。 (7)static int RIGHT:将Text对象和Image对象的锚点定位于对象右边的常数。 v 对于Image对象,并不存在BASELINE。其具体位置对应如图5-7所示。 图图5-7 5-7 锚点位置锚点位置 5.3.5 Image 类v Image 分为可变和不可变两种类型,不可变的Image是从资源文件,二进制数据,RGB数值,及其他Image直接创建的,一旦创建完成,Image 就无法再变化。 v 不可变的Image 通过Image.createImage(String name) 方法从指定的路径中读取创建Image所必需的数据,注意参数中的字符串必须以“/”开头,并且包括完整的名称。 v 可变的Image以指定的大小创建,它是可以修改的,可变的Image由Image.createImage(intwidth,int height)方法来创建,需要指定长宽,Image的其他显示特性和机器的显示屏完全一致。 v 但在显示时,显示屏在显示图像前都会先参照影像内存,然后当绘制速度慢到一定程度时,显示在屏幕上的画面会由前一帧画面的一部分和后一帧画面的一部分组成。 v 这样造成图像“撕裂”,为了解决这个问题,手机厂商可以从硬件上支持DoubleBuffer,即双缓冲区,这样显示屏绘图的时候可以使用一个影像内存来绘图。 v 另一个影像内存来进行程序绘图,这样交叉进行,可以避免画面撕裂的产生。双缓存技术是J2ME低级界面开发的关键技术之一。 5.3.6 字体类v Graphics 中还提供了对了对字体的控制方法,每个Graphics都有一个Font对象与其关联,来进行文字的渲染操作,调用其类方法setFont(null),即可使字体恢复到默认状态,对于具体的参数,Font提供了以下常量,来控制Font的属性。 v 字体大小:SMALL、MEDIUM、LARGE。v 字体外观:PROPORTIONAL、MONOSPACE、SYSTEM。v 字体风格:PLAIN、BOLD、ITALIC、UNDERLINED。 v static Font getFont(int face,int Style,int size):获得一个对象以表示字体所具有指定的外观,样式和大小。 v static Font getDefaultFont():获取系统的默认字体。 v 其中:v face参数,用来定义字体的外观,Font类定义的外观的常数如下。 (1)static int FACE_MONOSPACE:“定宽”字体外观,数值32被指定给此常。(2)static int FACE_PROPORTIONAL:“比例”字体外观,数值64被指定给此数。(3)static int FACE_SYSTEM:“系统”字体外观,数值0被指定给次参数。 v Style参数,用来定义字体的样式。Font类定义的样式参数。 (1)static int STYLE_PLAIN:样式常数“常规”,数值0被指定给此常数。 (2)static int STYLE_BOLD:样式常数“加粗”,数值1被指定给此常数。 (3)static int STYLE_ITALIC:样式常数“倾斜”,数值2被指定给此常数。 (4)static int STYLE_UNDERLINED:样式常数“加下划线”,数值4被指定给此常数。 v size参数,定义字体大小。Font类定义的字号大小常数。 (1)static int SIZE_LARGE:系统依赖性的“大”字号。 (2)static int SIZE_MEDIUM:系统依赖性的“中”字号。 (3)static int SIZE_SMALL:系统依赖性的“小”字号。 5.3.7 调整原点坐标v Graphics 类提供了一个可以调整屏幕坐标原点位置的方法:v void translate(int x, int y) 在当前坐标系统中把相关图形的左上角坐标位置改变为(x,y)点。 v 每次调用translate方法都是针对当前的坐标系统原点进行调整的,并不是以屏幕左上角调整的。 v 比如:当前坐标为(0,0),如果调用了translate(2,4)则当前原点坐标是原来屏幕的(2,4)坐标,如果再调用translate(3,4)则坐标(3,4)是相对于(2,3)的,所以相当于原始坐标系中的(5,7)。 v 获取重新定位的原点的方法:v int getTranslateX():获取左上角的横坐标。v int getTranslateY():获取左上角的纵坐标。 v 转换原点位置的最佳场合是当一张图片的大小比屏幕大时,以Screen为基础的图片显示,系统会自动提供上下卷动的功能,但是以Canvas为基础的图片显示时,系统并未提供卷动的功能,因此应如何卷动需要用户进行设计,这在设计游戏时尤为重要。 图图5-8 5-8 调整原点坐标调整原点坐标5.4 MIDP Timer APIv MIDP 中有这样一个API,它是一个可以简单地实现多任务调度执行的定时器类,调度由一个后台线程完成。使得 J2ME 开发人员从中受益。 v J2ME 提示了两个类用来定义和调试任务, 他们分别是 TimerTask 和 Timer。TimerTask 是用户定义的需要被调度的所有任务的抽象基类。 v Timer 类在任务执行的时候负责创建和管理执行线程。要定义一个任务,定义一个 TimerTask 的子类,并实现 run 方法。 v 例如:vpublic class MyTask extends TimerTaskvv public void run()v v vSystem.out.println( Running the task );v v v schedule()共有四个重载方法;每一个任务都可以在一个特定的时间点(使用一个 Date 对象指定)或者延时特定的时间段(以毫秒为单位)之后执行。 v 你可以安排这个任务只执行一次或者在一个特定的时间段里反复执行。Timer 还提供了一个 scheduleAtFixedRate 方法来根据该任务第一次执行的时间来指定反复执行时延长的时间段。 v 如果一个任务被延时了,被安排在后面执行的任务就被相应地缩短等待时间以“接上”被延时的任务。每个 Timer 对象都会创建和管理一个后台线程。 v 一般情况下,一个程序创建一个 Timer 就够了,当然也可以根据需要创建任意多个。通过调用cancel方法,你还可以在任何时候停止一个 Timer 并终止后台线程。 v 但要注意的是,一旦 Timer 被终止了,就不可能再恢复执行,除非你重新生成一个 Timer 对象并重新安排你想要执行的任务。 v Timer 对象是线程安全的,你可以在多线程的环境下直接访问 Timer 对象,而不用任何显式的同步处理。另外,每个任务提供了一个 cancel 方法(继承自 TimerTask 基类),你可以在任务执行的过程当中调用该方法来终止该任务。 v 一旦你终止了该任务,那么它将退出任务调度。你可以在任何时间调用任务的 cancel 方法来终止该任务的执行,哪怕该任务还一次都没有执行过。 v 下面提供了一个简示的 MIDlet 示例来演示 Timer 的使用,程序利用定时器来模拟一个星空移动的效果。星星用一个点来表示,这使用到了低级界面图形API。5.5 综合实例:编写欢迎界面v 欢迎界面是指程序启动时首先显示的一个欢迎画面,可以是一幅图片也可以是其他信息。用户可以通过按键跳过欢迎画面,当欢迎画面程序内设定的时间到时,也可以自动消失。 v 由于它只显示一段时间,我们可以使用上节学习的Timer定时器来对它进行控制。 v 由于是欢迎界面,所以当时间到了或者用户按下了跳过按钮程序要能够进入主界面,因此需要用构造方法传递Display对象和主程序的Displayable对象。当需要切换到主画面时,使用setCurrent方法就可以切换了。 图图5-9 5-9 欢迎界面欢迎界面 图图5-10 5-10 主界面主界面 5.6 小 结v 本章重点讲解了MIDP低级API方法在屏幕上绘制图片、字体和自定义控件及事件处理,程序员对这些低级API方法有高度的自主开发权,所以可以制作出丰富多彩的界面来,但这需要花费大量的开发时间。读者需要大量的练习才能灵活运用。
展开阅读全文