按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
内部类WL 和main()方法是加入程序片的唯一两个元素,程序片剩余的部分则原封未动。事实上,我们通常
将WL 类和main()方法做一结小的改进复制和粘贴到我们自己的程序片里(请记住创建内部类时通常需要一
个外部类来处理它,形成它静态地消除这个需要)。我们可以看到在 main()方法里,程序片明确地初始化和
开始,因为在这个例子里浏览器不能为我们有效地运行它。当然,这不会提供全部的浏览器调用 stop()和
destroy()的行为,但对大多数的情况而言它都是可接受的。如果它变成一个麻烦,我们可以:
(1) 使程序片句柄为一个静态类(以代替局部可变的main()),然后:
(2) 在我们调用 System。exit()之前在 WindowAdapter。windowClosing()中调用applet。stop()和
applet。destroy()。
注意最后一行:
aFrame。setVisible(true);
这是Java 1。1 AWT 的一个改变。show()方法不再被支持,而 setVisible(true)则取代了show()方法。当我
们在本章后面部分学习 Java Beans 时,这些表面上易于改变的方法将会变得更加的合理。
这个例子同样被使用TextField 修改而不是显示到控制台或浏览器状态行上。在开发程序时有一个限制条件
就是程序片和应用程序我们都必须根据它们的运行情况选择输入和输出结构。
这里展示了 Java 1。1 AWT 的其它小的新功能。我们不再需要去使用有错误倾向的利用字符串指定
BorderLayout 定位的方法。当我们增加一个元素到Java 1。1 版的BorderLayout 中时,我们可以这样写:
aFrame。add(applet; BorderLayout。CENTER);
我们对位置规定一个BorderLayout 的常数,以使它能在编译时被检验(而不是对老的结构悄悄地做不合适的
事)。这是一个显著的改善,并且将在这本书的余下部分大量地使用。
2。 将窗口接收器变成匿名类
任何一个接收器类都可作为一个匿名类执行,但这一直有个意外,那就是我们可能需要在其它场合使用它们
的功能。但是,窗口接收器在这里仅作为关闭应用程序窗口来使用,因此我们可以安全地制造一个匿名类。
然后,main()中的下面这行代码:
aFrame。addWindowListener(new WL());
会变成:
aFrame。addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System。exit(0);
}
});
这有一个优点就是它不需要其它的类名。我们必须对自己判断是否它使代码变得易于理解或者更难。不过,
对本书余下部分而言,匿名内部类将通常被使用在窗口接收器中。
3。 将程序片封装到JAR 文件里
一个重要的 JAR 应用就是完善程序片的装载。在Java 1。0 版中,人们倾向于试法将它们的代码填入到单个的
程序片类里,因此客户只需要单个的服务器就可适合下载程序片代码。但这不仅使结果凌乱,难以阅读(当
然维护也然)程序,但类文件一直不能压缩,因此下载从来没有快过。
JAR 文件将我们所有的被压缩的类文件打包到一个单个儿的文件中,再被浏览器下载。现在我们不需要创建
一个糟糕的设计以最小化我们创建的类,并且用户将得到更快地下载速度。
仔细想想上面的例子,这个例子看起来像 Button2NewB,是一个单类,但事实上它包含三个内部类,因此共
有四个。每当我们编译程序,我会用这行代码打包它到一个JAR 文件:
jar cf Button2NewB。jar *。class
这是假定只有一个类文件在当前目录中,其中之一来自Button2NewB。java (否则我们会得到特别的打包)。
现在我们可以创建一个使用新文件标签来指定 JAR 文件的HTML 页,如下所示:
Button2NewB Example Applet
415
…………………………………………………………Page 417……………………………………………………………
与HTML 文件中的程序片标记有关的其他任何内容都保持不变。
13。16。4 再研究一下以前的例子
为注意到一些利用新事件模型的例子和为学习程序从老到新事件模型改变的方法,下面的例子回到在本章第
一部分利用事件模型来证明的一些争议。另外,每个程序包括程序片和应用程序现在都可以借助或不借助浏
览器来运行。
1。 文本字段
这个例子同 TextField1。java 相似,但它增加了显然额外的行为:
//: TextNew。java
// Text fields with Java 1。1 events
import java。awt。*;
import java。awt。event。*;
import java。applet。*;
public class TextNew extends Applet {
Button
b1 = new Button(〃Get Text〃);
b2 = new Button(〃Set Text〃);
TextField
t1 = new TextField(30);
t2 = new TextField(30);
t3 = new TextField(30);
String s = new String();
public void init() {
b1。addActionListener(new B1());
b2。addActionListener(new B2());
t1。addTextListener(new T1());
t1。addActionListener(new T1A ());
t1。addKeyListener(new T1K());
add(b1);
add(b2);
add(t1);
add(t2);
add(t3);
}
class T1 implements TextListener {
public void textValueChanged(TextEvent e) {
t2。setText(t1。getText());
}
}
class T1A implements ActionListener {
private int count = 0;
public void actionPerformed(ActionEvent e) {
t3。setText(〃t1 Action Event 〃 + count++);
416
…………………………………………………………Page 418……………………………………………………………
}
}
class T1K extends KeyAdapter {
public void keyTyped(KeyEvent e) {
String ts = t1。getText();
if(e。getKeyChar() ==
KeyEvent。VK_BACK_SPACE) {
// Ensure it's not empty:
if( ts。length() 》 0) {
ts = ts。substring(0; ts。length() 1);
t1。setText(ts);
}
}
else
t1。setText(
t1。getText() +
Character。toUpperCase(
e。getKeyChar()));
t1。setCaretPosition(
t1。getText()。length());
// Stop regular character from appearing:
e。consume();
}
}
class B1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
s = t1。getSelectedText();
if(s。length() == 0) s = t1。getText();
t1。setEditable(true);
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
t1。setText(〃Inserted by Button 2: 〃 + s);
t1。setEditable(false);
}
}
public static void main(String'' args) {
TextNew applet = new TextNew();
Frame aFrame = new Frame(〃TextNew〃);
aFrame。addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System。exit(0);
}
});
aFrame。add(applet; BorderLayout。CENTER);
aFrame。setSize(300;200);
applet。init();
applet。start();
aFrame。setVisible(true);
}
417
…………………………………………………………Page 419……………………………………………………………
} ///:~
当TextField t1 的动作接收器被激活时,TextField t3 就是一个需要报告的场所。我们注意到仅当我们按
下“enter”键时,动作接收器才会为“TextField”所激活。
TextField t1 附有几个接收器。T1 接收器从 t1 复制所有文字到t2,强制所有字符串转换成大写。我们会发
现这两个工作同是进行的,并且如果我们增加 T1K 接收器后我们再增加T1 接收器,它就不那么重要:在文字
字段内的所有的字符串将一直被强制变为大写。这看起来键盘事件一直在文字组件事件前被激活,并且如果
我们需要保留t2 的字符串原来输入时的样子,我们就必须做一些特别的工作。
T1K 有着其它的一些有趣的活动。我们必须测试backspace (因为我们现在控制着每一个事件)并执行删除。
caret 必须被明确地设置到字段的结尾;否则它不会像我们希望的运行。最后,为了防止原来的字符串被默
认的机制所处理,事件必须利用为事件对象而存在的consume()方法所“耗尽”。这会通知系统停止激活其
余特殊事件的事件处理器。
这个例子同样无声地证明了设计内部类的带来的诸多优点。注意下面的内部类:
class T1 implements TextL istener {
public void textValueChanged(TextEvent e) {
t2。setText(t1。getText());
}
}
t1 和 t2 不属于 T1 的一部分,并且到目前为止它们都是很容易理解的,没有任何的特殊限制。这是因为一个
内部类的对象能自动地捕捉一个句柄到外部的创建它的对象那里,因此我们可以处理封装类对象的方法和内
容。正像我们看到的,这十分方便(注释⑥)。
⑥:它也解决了“回调”的问题,不必为 Java 加入任