《汉字知多少》开发志(二)

类别:Java 点击:0 评论:0 推荐:

通过Font类的宽度函数和高度函数解决了字符重叠的问题,下一步就是稳定显示的问题咯。

把半年前写的一个例子拿来看,其中也是关于固定背景上面更新的内容,一运行不要紧,在moto i85s中能运行,但是总是不停提示出错,而在motorola j2me Launchpad中压根儿就不能运行,画面都没有出就开始报错。咋回事?!后来下载motorola A388手机倒是可以运行,但是软键exitCommand不能正确显示,每次都得强行退出。晕……


 仔细看了源码,大体思路就是通过一个函数makebackground每次对固定的内容进行重画,而在paint中调用这个函数,再进行其它写字符串等操作。通过艰苦的追踪,发现每次执行到背景外可变信息重画时出错。看了看Canvas的帮助文件,通过这种方式固定背景重画其实一点实际意义都没有!汗……

先把其它信息的更新注释掉,然后声明了一个Image,在构建器中把固定背景信息画到上面,然后每次在paint中调用drawImage,呵呵,成功,在i85s和388模拟器中都运行成功。然后开始在背景上画需要更新的信息,显示文本,ok,画线,也ok,但是在drawImage时出错,这个Image从一个图标文件得来,应该是immutable属性。难道问题在这里???me先看了看jar的包含信息,晕,居然没有包含这个图标文件。呵呵,怪不得!点选后,再次编译、运行,还是不行!还是老老实实看看api doc吧。下面是Canvas中paint函数的说明文档。


 Renders the Canvas. The application must implement this method in order to paint any graphics.渲染画布。
 程序必须实现这个方法以画出图形。
 The Graphics object's clip region defines the area of the screen that is considered to be invalid. A correctly-written paint() routine must paint every pixel within this region. Applications must not assume that they know the underlying source of the paint() call and use this assumption to paint only a subset of the pixels within the clip region. The reason is that this particular paint() call may have resulted from multiple repaint() requests, some of which may have been generated from outside the application. An application that paints only what it thinks is necessary to be painted may display incorrectly if the screen contents had been invalidated by, for example, an incoming telephone call.
 Graphics对象剪切区指定了屏幕的部分区域,这部分区域对屏幕来说是无效的(也就是不对它作用)。正确书写的paint()方法必须画出这个区域的每个像素。程序一定不要认为已经完全知晓paint()在哪里被调用,并因为这种假设而只画出剪切区的部分像素。原因在于这个paint()调用可能是调用repaint()而引起的,而后者完全可能在该程序之外发生。一个只画出自认为需要画的部分的程序,如果屏幕被比如呼入的电话破坏(?)时可能不会正常显示。
 Operations on this graphics object after the paint() call returns are undefined. Thus, the application must not cache this Graphics object for later use or use by another thread. It must only be used within the scope of this method.
 调用paint()方法后再对这个grapchis对象进行的操作是没有定义(?实现)的。因此,一定不要对它进行缓存以待后用或者被其它的线程调用。它只能在这个方法的视野之内使用。
 The implementation may postpone visible effects of graphics operations until the end of the paint method.
 在paint()方法执行完毕之前,所有方法中的操作(?实现)会延迟graphics操作的可视效果
 The contents of the Canvas are never saved if it is hidden and then is made visible again. Thus, shortly after showNotify() is called, paint() will always be called with a Graphics object whose clip region specifies the entire displayable area of the Canvas. Applications must not rely on any contents being preserved from a previous occasion when the Canvas was current. This call to paint() will not necessarily occur before any other key, pointer, or commandAction() methods are called on the Canvas. Applications whose repaint recomputation is expensive may create an offscreen Image, paint into it, and then draw\ this image on the Canvas when paint() is called.
 如果被隐藏然后再重新显示,Canvas的所有内容都不会被保存下来。因此,在调用showNotify()方法后,Graphics对象总是会调用paint()方法。该Graphics对象的剪切区指定了Canvas所有可以显示的区域。当Canvas成为当前屏幕时,程序一定不要依赖上次出现时Canvas上显示的内容,并且这次对paint()的调用不需要出现在任何键、触摸笔或者commandAction()等方法被Canvas调用之前。repaint重算代价比较大的程序可以创建一个非当前显示的Image,把内容画在上面,然后在Canvas的paint()方法中调用drawImage进行显示。
 The application code must never call paint(); it is called only by the implementation.
 程序代码中永远不要直接调用paint();它只能被其它实现(?)调用。
 The Graphics object passed to the paint() method has the following properties:
  the destination is the actual display, or if double buffering is in effect, a back buffer for the display
  the clip region includes at least one pixel within this Canvas
  the current color is black
  the font is the same as the font returned by Font.getDefaultFont()
  the stroke style is SOLID
  the origin of the coordinate system is located at the upper-left corner of the Canvas
  the Canvas is visible, that is, a call to isShown() will return true
 传递给paint()方法的Graphics对象必须有以下属性:
  目标是实际的显示,如果支持双缓冲的话也可以是用于显示的后台缓冲
  剪切区最少包含当前Canvas的一个像素
  当前的颜色是黑色
  字体和通过Font.getDefaultFont()返回的字体一样
  画笔样式是SOLID
  坐标原点位于Canvas的左上角
  Canvas是可视的,也就是说,调用isShow()应该返回真值
 
 虽然没有发现能直接解决问题的内容,但也算有收获,比如在paint()中需要对整个画布进行重画。继续调试,用try catch把那个出问题的drawImage给包含起来,噢,能运行了,不过还是不停显示一堆错误,查阅api docs,出错有两种可能一种为IllegalArgumentException(if anchor is not a legal value),另外一种就是名声远扬的NullPointerException(if img is null)。哈哈,肯定是锚点的问题,因为me已经提前测试img了,确保是正确的。看看锚点出了什么问题,那句是这样的:
 g.drawImage(img,width/2,height/2-20,g.BASELINE|g.HCENTER);
 霍霍,通过查阅资料,原来Image不支持BASELINE锚点!也是,它不想TEXT那样有基线,如果要定位为中间可以用VCENTER。


 继续回归主题。

屏幕的闪动通过后台生成Image,然后在paint()中drawImage的方式进行解决,效果非常理想,呵呵,终于搞定了。不过在机器上测试的时候,显示出非常多的?出来,可能是motorola A388上带的字库没有电脑上模拟器中支持的大吧。算了,太困,觉觉去也……

本文地址:http://com.8s8s.com/it/it14984.htm