其名称以 DrawableSequencer 开始的类负责创建并维护 Drawable 对象的有序集。这个集合可以编辑、可以在 DrawingContext 上描绘、可以存储到文件中,或者从文件装入。
每个对象根据绘制优先级排序。优先级较低(在数学意义上)的对象排列在优先级较高的对象后面。如果优先级较高的对象不透明,那么它将隐藏紧跟在它后面的优先级较低的对象。多个对象可能有相同的优先级。不指定相同优先级对象的相对绘图顺序。
DrawableSequencer 的编辑能力包括添加对象、除去对象或者除去所有的对象。通过除去对象,然后根据不同的优先级进行添加来重新排列对象。
DrawableSequencer 支持符合 java.util.Enumeration 的对象的创建。可以使用它们访问包含在序列中的对象。提供了两个枚举类型:
无限制:集合中的所有 Drawable 对象将按照优先级顺序被查看。
限制范围:其优先级值在指定的值范围之间(包括边界值)的集合中的所有 Drawable 对象按照优先级顺序被查看。如果高值小于低值,那么将看不到对象。
存储方法
当使用自存储持久性时, DrawableSequencer 提供服务来将它的对象持久地存储到文件中,并在稍后重新装入它们。重新装入一组已保存对象的集合意味着根据优先级将它们添加到现有的序列中。要用文件中的对象替换序列,必须首先从序列中除去所有对象。
当使用 Java 的 ObjectStream 持久性时, DrawableSequencer 提供了静态 loadFrom() 和 storeIn() 方法,它们使用 ObjectStreams 来装入和存储 Drawables 。这个机制总是替代现有的可绘制对象的内容。
在“自存储”方法中,每个对象通过它实例上的方法装入或者存储其本身。在 ObjectStream 持久性方法中,每个对象由外部应用的逻辑来保存或装入。因此,我更喜欢“自存储”方法。
在下面各节中,我们将讨论与类 DrawableSequencer 有关的每个类的定义和用法。
类 DrawableSequencer
类 DrawableSequencer 提供了上述支持。清单 8 是类 DrawableSequencer 的定义。
清单 8. 类 DrawableSequencer
2 {
3 private Vector _items; // ordered items in list
4 // add new drawable
5 public void addAt(Drawable drawable, int priority) {
6 int i;
7 // insert element at proper priority; higher priorities come last
8 for(i = 0; i < _items.size(); i++) {
9 if(priority <= dso.priority) // past all lower priorities elements
10 break;
11 }
12 _items.insertElementAt(new DrawableSequencerObject(priority, drawable), i);
13 }
14 // remove all drawables
15 public void removeAll() {
16 _items.removeAllElements();
17 }
18 // remove a drawable
19 public void remove(Drawable drawable) throws NoSuchElementException {
20 int i, size = _items.size();
21 // find element to remove
22 for(i = 0; i < size; i++) {
23 DrawableSequencerObject dso =
24 (DrawableSequencerObject)_items.elementAt(i);
25 if(drawable == dso.drawable) // must be the same (vs equal)
26 break;
27 }
28 if(i < size) // found one
29 _items.removeElementAt(i);
30 else
31 throw new NoSuchElementException(
32 "DrawableSequencer.remove() - drawable not found");
33 }
34 // get enumerator for all
35 public Enumeration elements() {
36 return elements(Integer.MIN_VALUE, Integer.MAX_VALUE);
37 }
38 // get enumerator for range
39 public Enumeration elements(int low, int high) {
40 return new DrawableSequencerEnumerator(_items, low, high);
41 }
42 // draw all matching drawables
43 protected void drawSelected(DrawingContext context, Enumeration e) {
44 // walk all drawables, and draw them
45 while(e.hasMoreElements()) {
46 Drawable d = (Drawable)e.nextElement();
47 d.draw(context); // draw current drawable
48 }
49 }
50 // draw all drawables
51 public void draw(DrawingContext context) {
52 drawSelected(context, elements());
53 }
54 // draw selected drawables
55 public void draw(DrawingContext context, int min, int max) {
56 drawSelected(context, elements(min, max));
57 }
58 }
59
loadFrom() 和 storeOn() 方法为包含在 DrawableSequencer 中的 Drawable 对象提供持久性支持。当需要每个文件的单个序列时,文件形式是很方便的。流形式使用一个现有的流。这样多个序列可以存储在一个流上。
清单 9 定义类 DrawableSequencer 的持久性服务。
清单 9. 类 DrawableSequencer的持久性服务
2 public void storeOn(DataOutputStream dos) throws IOException {
3 // walk all drawables, and store them
4 Enumeration e = _items.elements();
5 dos.writeInt(_items.size()); // write total count
6 while(e.hasMoreElements()) {
7 DrawableSequencerObject dso =
8 (DrawableSequencerObject)e.nextElement();
9 Drawable drawable = dso.drawable;
10 int priority = dso.priority;
11 dos.writeInt(priority); // write priority
12 dos.writeUTF(drawable.getClass().getName()); // then class name
13 drawable.storeOn(dos); // then class instance variables
14 dos.flush();
15 }
16 }
17 // store all on a stream
18 public void storeOn(File f) throws IOException {
19 FileOutputStream fos = new FileOutputStream(f);
20 BufferedOutputStream bos = new BufferedOutputStream(fos);
21 DataOutputStream dos = new DataOutputStream(bos);
22 storeOn(dos); // store myself
23 dos.close();
24 }
25 // load all from a stream
26 public void loadFrom(DataInputStream dis) throws IOException,
27 ClassNotFoundException, InstantiationException, IllegalAccessException {
28 int drawableCount; // number of objects in stream
29 // load all names
30 try {
31 // walk all stored drawables, and load them
32 drawableCount = dis.readInt();
33 for(int count = 0; count < drawableCount; count++) {
34 int priority = dis.readInt();
35 String className = dis.readUTF();
36 Class classObject = Class.forName(className);
37 Object object = classObject.newInstance();
38 if(!(object instanceof Drawable))
39 throw new ClassNotFoundException(className + " not a subclass of Drawable");
40 Drawable drawable = (Drawable)object;
41 drawable.loadFrom(dis);
42 addAt(drawable, priority);
43 }
44 }
45 catch(EOFException ex) { // map exception
46 throw new ClassNotFoundException(ex.getMessage());
47 }
48 }
49 // load all drawables from a file
50 public void loadFrom(File f) throws IOException,
51 ClassNotFoundException, InstantiationException, IllegalAccessException {
52 FileInputStream fis = new FileInputStream(f); // get a data stream to a file
53 BufferedInputStream bis = new BufferedInputStream(fis);
54 DataInputStream dis = new DataInputStream(bis);
55 loadFrom(dis); // load myself
56 dis.close();
57 }
58
类 DrawableSequencerObject
类 DrawableSequencerObject 表示存储在 DrawableSequencer 中的信息。 它记录 Drawable 对象和它的优先级。这个类不是公用的,因为只能由 DrawableSequencer 使用它。清单 10 是类 DrawableSequencerObject 的定义。
清单 10. 类DrawableSequencerObject
2 {
3 public int priority; // relative position selector
4 public Drawable drawable; // actual item to draw
5 }
6
类 DrawableSequencerEnumerator
类 DrawableSequencerEnumerator 提供了服务来迭代 DrawableSequencer 中的对象。本质上,它是 C 结构,并且记录鼠标的当前位置和选择范围的高低值。这个类不是公共的,因为它是由 DrawableSequencer 的方法创建的,并且符合公共接口 java.util.Enumeration 。
由于 DrawableSequencer 使用 java.util.Vector 来存放 Drawable 对象,所以枚举器只增加索引值来在序列中前进。不在期望范围内的值被跳过。索引总是在待访问序列的下一个对象上设置,或者越过最后一个对象设置。
清单 11 是类 DrawableSequencerEnumerator 的定义。
清单 11. 类DrawableSequencerEnumerator
2 {
3 private int _index; // relative position selector
4 private Vector _vector; // enumerate over this
5 private int _low, _high; // range selectors
6 public DrawableSequencerEnumerator(Vector vector, int low, int high) {
7 _vector = vector;
8 _low = low; _high= high;
9 // advance while outside of range to set to first
10 for(_index = 0; _index < _vector.size(); _index++) {
11 int priority =
12 ((DrawableSequencerObject)_vector.elementAt(_index)).priority;
13 if(priority >= _low && priority <= _high) // in range
14 break;
15 }
16 }
17 // test for done
18 public boolean hasMoreElements() {
19 return _index < _vector.size();
20 }
21 // get current and advance
22 public Object nextElement() {
23 Object result =
24 ((DrawableSequencerObject)_vector.elementAt(_index)).drawable;
25 // advance while inside of range to set to next
26 for(_index++; _index < _vector.size(); _index++) {
27 int priority =
28 ((DrawableSequencerObject)_vector.elementAt(_index)).priority;
29 if(priority >= _low && priority <= _high) // in range
30 break;
31 }
32 return result;
33 }
34 }
35