J2ME UI接口的需求:
1. 设备和应用程序应该易用
2. 设备和应用程序应该在用户无法集中注意力的时候使用
3. 组成元素和ui概念在设备间有很大差距,特别跟桌面系统比较。
4. MID上的应用应该有跟原生系统兼容的UI,以便用户使用
不采用AWT的方案,因为:
1. AWT是基于桌面计算机的
2. 当ui跟AWT交互,动态产生的事件对象是短命而且只在事件被处理前存在,之后,对象成为垃圾增加系统负担
3. awt有丰富但是依赖于桌面系统的特性,包括一些在MID上找不到的特性,如窗口管理(重叠,缩放),当MID相对较小的显示,并不需要这些功能,所以这套窗口和排版在mid不适用
4. awt组件是用来跟指针设备交互的,如鼠标或笔。但是这只对少数MID设备成立
高级UI:javax.microedition.lcdui.Screen
1. 实际的绘制是由其实现,程序无法定制外观,如形状,颜色,字体等
2. 导航,滚动,其他原始的交互都是由其封装,应用程序无需处理
3. 程序无法使用特定的输入设备如特定的键值
底层UI:Canvas ,Graphics
1. 控制绘制显示
2. 监听事件,如按键动作
3. 访问特定的键值或输入设备
类层次结构:
1. 中心的抽象是Displayable,封装了设备相关的渲染工作和用户输入。每次只有一个课件的Displayable对象。
2. Screen继承自Displayable,负责高级UI控件的交互,Screen的子类负责渲染,交互,移动,滚动,而只有高层的事件才会发送到程序,这样的设计理由出于对MIDP设备上不同的显示和输入方法的考虑。这些差异使得不同的组件布局,滚动和焦点移动在不同的设备上实现,如果应用程序必须处理这样的事件,移动性会受到损害。
三种displayable对象
i. Screen 封装了复杂的用户接口组件(如List和TextBox),Screen的结构是预先定义好的,应用程序不能添加其他组件到Screen
ii. 通用的Screen(Form的实例)可以包含Item对象(UI控件),程序可在Form上添加任意数量的text,image,和其他控件,但是建议把Form保持简单,只保存几个,关系紧密的UI组件
iii. 在底层api下使用的Screen(如Canvas的子类)
事件处理机制:
Ui产生事件,实现产生回调来告知程序事件的发生。有四种UI回调:
1. 虚command(高级API)
2. 底层事件(按键,触摸笔)
3. Canvas.paint()的调用
4. Display.callSerially 产生的Runnable对象的run方法
所有的UI回调都是序列号的,不会并发。
一个例外的情况是Canvas.serviceRepaints。直接导致Canvas.paint并等待其返回
可序列化的回调函数:
• Canvas.hideNotify
• Canvas.keyPressed
• Canvas.keyRepeated
• Canvas.keyReleased
• Canvas.paint
• Canvas.pointerDragged
• Canvas.pointerPressed
• Canvas.pointerReleased
• Canvas.showNotify
• Canvas.sizeChanged
• CommandListener.commandAction
• CustomItem.getMinContentHeight
• CustomItem.getMinContentWidth
• CustomItem.getPrefContentHeight
• CustomItem.getPrefContentWidth
• CustomItem.hideNotify
• CustomItem.keyPressed
• CustomItem.keyRepeated
• CustomItem.keyReleased
• CustomItem.paint
• CustomItem.pointerDragged
• CustomItem.pointerPressed
• CustomItem.pointerReleased
• CustomItem.showNotify
• CustomItem.sizeChanged
• CustomItem.traverse
• CustomItem.traverseOut
• Displayable.sizeChanged
• ItemCommandListener.commandAction
• ItemStateListener.itemStateChanged
• Runnable.runresulting from a call to Display.callSerially
注意:Timer事件不是UI事件,Timer回调可能跟UI回调同步发生,即使同一个Timer的TimerTask回调是序列化的。
使用Timer的程序必须保护他们的数据,以免其他timer线程和ui回调的并发访问。可以选择在timer回调里面使用Display.callSerially来使timer事件跟ui回调序列化进行
Abstract commands抽象命令
因为MIDP是高度抽象的,所以它不假设特定的用户交互技术,如软件和菜单。同样,底层的用户交互,如traversal和scrolling是不对程序可见的。MIDP程序定义Commands, 而底层实现可能通过软键,菜单来实现它,或其他任何合适的方式。
Command通过addCommand来安装到Displayable
设备的原始风格可能将特定类型的command放到标准的位置,如go-back操作经常放在右软键,command允许应用程序来跟实现中这样的语义通信,所以标准的映射能发挥作用
实现可能并没有实现Command的所有语义,Command的属性至少用来映射到特定的ui,而实际的command语义在commandListener实现
设备提供的操作:
在许多高级UI中有一些额外的UI操作,这些操作不对应用程序可见,至少对用户可见。这些操作的集合取决于特定设备的用户接口的设计。例如,一个操作允许用户在文本输入时在英文和数字之间切换输入法,这是在只有ITU-T键盘的设备上需要的。更加复杂的输入系统,会需要额外的操作。有些操作是采用应用程序特定命令的定义方法来呈现。用户不需要理解每一个实现的操作。例如,一个有基于文本查找的文本输入会在TextBox里面提供额外的功能。没有这个输入机制的系统没有这种功能。不同输入模式的可用性应该在java和原始系统之间保持一致。这意味着,例如,如果一个可以预见的文本输入模式是在原始系统可用,它应该在java应用程序中也可用。
有些操作在所有的设备都有,但是每一个实现都有点不同。例如,在List和Form的item之间移动,选择List元素,在文本编辑器中移动插入点等。有些设备不支持之间修改item的值,需要用户转移到另外一个屏幕的编辑器。在这些设备中,应该有一个精心安排的选择操作,来调用另外一个屏幕的编辑器。选择List的元素,可用是Go,Select或其他的键值。有些设备没有特定的选择键,必须用其他方式选择元素。
有些有特定选择键的设备,这个键通常有一个标签,在他的意思是明显的时候,实现可用这个键。例如,如果用户面对一堆互斥选项,选择键只会选择其中一个,在没有特定选择键的设备,很有可能用一个有标签的软件操作来完成选择。J2ME为了让你在操作发生时候接受通知,允许你设置一个IMPLICIT的选择项给List,也允许你设置一个item的默认键
高层事件API:基于监听模式,Screen,Canvas都可以有command的监听器,
相关方法,void commandAction(Command c, Displayable d);
void itemStateChanged(Item item);
底层事件API:
键盘相关:
public void keyPressed(int keyCode);
public void keyReleased(int keyCode);
public void keyRepeated(int keyCode);
public void keyPressed(int keyCode);
public void keyReleased(int keyCode);
public void keyRepeated(int keyCode);
public static int getGameAction(int keyCode);
public static int getKeyCode(int gameAction); where gameAction is UP,DOWN, LEFT, RIGHT, FIRE, etc.
例子:
class MovingBlocksCanvas extends Canvas {
public void keyPressed(int keyCode) {
int action = getGameAction(keyCode);
switch (action) {
case LEFT:
moveBlockLeft();
break;
case RIGHT:
...
}
}
}
触摸笔相关:
public void pointerReleased(int x, int y);
public void pointerDragged(int x, int y);
public void pointerPressed(int x, int y);
public static boolean hasPointerEvents();
public static boolean hasPointerMotionEvents();