友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
Java编程思想第4版[中文版](PDF格式)-第71部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
this。color = color;
}
public void paint(Graphics g) {
g。setColor(color);
int rnd = 30;
g。fillRoundRect(0; 0; size()。width;
size()。height; rnd; rnd);
g。setColor(Color。black);
397
…………………………………………………………Page 399……………………………………………………………
g。drawRoundRect(0; 0; size()。width;
size()。height; rnd; rnd);
FontMetrics fm = g。getFontMetrics();
int width = fm。stringWidth(label);
int height = fm。getHeight();
int ascent = fm。getAscent();
int leading = fm。getLeading();
int horizMargin = (size()。width width)/2;
int verMargin = (size()。height height)/2;
g。setColor(Color。white);
g。drawString(label; horizMargin;
verMargin + ascent + leading);
}
public boolean keyDown(Event evt; int key) {
TextField t =
(TextField)parent。h。get(〃keyDown〃);
t。setText(evt。toString());
return true;
}
public boolean keyUp(Event evt; int key) {
TextField t =
(TextField)parent。h。get(〃keyUp〃);
t。setText(evt。toString());
return true;
}
public boolean lostFocus(Event evt; Object w) {
TextField t =
(TextField)parent。h。get(〃lostFocus〃);
t。setText(evt。toString());
return true;
}
public boolean gotFocus(Event evt; Object w) {
TextField t =
(TextField)parent。h。get(〃gotFocus〃);
t。setText(evt。toString());
return true;
}
public boolean
mouseDown(Event evt;int x;int y) {
TextField t =
(TextField)parent。h。get(〃mouseDown〃);
t。setText(evt。toString());
return true;
}
public boolean
mouseDrag(Event evt;int x;int y) {
TextField t =
(TextField)parent。h。get(〃mouseDrag〃);
t。setText(evt。toString());
return true;
}
public boolean
398
…………………………………………………………Page 400……………………………………………………………
mouseEnter(Event evt;int x;int y) {
TextField t =
(TextField)parent。h。get(〃mouseEnter〃);
t。setText(evt。toString());
return true;
}
public boolean
mouseExit(Event evt;int x;int y) {
TextField t =
(TextField)parent。h。get(〃mouseExit〃);
t。setText(evt。toString());
return true;
}
public boolean
mouseMove(Event evt;int x;int y) {
TextField t =
(TextField)parent。h。get(〃mouseMove〃);
t。setText(evt。toString());
return true;
}
public boolean mouseUp(Event evt;int x;int y) {
TextField t =
(TextField)parent。h。get(〃mouseUp〃);
t。setText(evt。toString());
return true;
}
}
public class AutoEvent extends Applet {
Hashtable h = new Hashtable();
String'' event = {
〃keyDown〃; 〃keyUp〃; 〃lostFocus〃;
〃gotFocus〃; 〃mouseDown〃; 〃mouseUp〃;
〃mouseMove〃; 〃mouseDrag〃; 〃mouseEnter〃;
〃mouseExit〃
};
MyButton
b1 = new MyButton(this; Color。blue; 〃test1〃);
b2 = new MyButton(this; Color。red; 〃test2〃);
public void init() {
setLayout(new GridLayout(event。length+1;2));
for(int i = 0; i 《 event。length; i++) {
TextField t = new TextField();
t。setEditable(false);
add(new Label(event'i'; Label。CENTER));
add(t);
h。put(event'i'; t);
}
add(b1);
add(b2);
}
399
…………………………………………………………Page 401……………………………………………………………
} ///:~
我们可以看到构建器使用利用自变量同名的方法,所以自变量被赋值,并且使用 this 来区分:
this。label = label;
paint()方法由简单的开始:它用按钮的颜色填充了一个“圆角矩形”,然后画了一个黑线围绕它。请注意
size()的使用决定了组件的宽度和长度(当然,是像素)。这之后,paint()看起来非常的复杂,因为有大量
的预测去计算出怎样利用“font metrics”集中按钮的标签到按钮里。我们能得到一个相当好的关于继续关
注方法调用的主意,它将程序中那些相当平凡的代码挑出,当我们想集中一个标签到一些组件里时,我们正
好可以对它进行剪切和粘贴。
您直到注意到AutoEvent 类才能正确地理解 keyDown();keyUp()及其它方法的运行。这包含一个Hashtable
(译者注:散列表)去控制字符串来描述关于事件处理的事件和TextField 类型。当然,这些能被静态的创
建而不是放入Hashtable 但我认为您会同意它是更容易使用和改变的。特别是,如果我们需要在AutoEvent
中增加或删除一个新的事件类型,我们只需要简单地在事件列队中增加或删除一个字符串——所有的工作都
自动地完成了。
我们查出在 keyDown(),keyup()及其它方法中的字符串的位置回到 myButton 中。这些方法中的任何一个都
用父句柄试图回到父窗口。父类是一个AutoEvent,它包含Hashtable h 和get()方法,当拥有特定的字符串
时,将对一个我们知道的TextField 对象产生一个句柄(因此它被选派到那)。然后事件对象修改显示在
TextField 中的字符串陈述。从我们可以真正注意到举出的例子在我们的程序中运行事件时以来,可以发现
这个例子运行起来颇为有趣的。
13。14 程序片的局限
出于安全缘故,程序片十分受到限制,并且有很多的事我们都不能做。您一般会问:程序片看起来能做什
么,传闻它又能做什么:扩展浏览器中WEB 页的功能。自从作为一个网上冲浪者,我们从未真正想了解是否
一个WEB 页来自友好的或者不友好的站点,我们想要一些可以安全地行动的代码。所以我们可能会注意到大
量的限制:
(1) 一个程序片不能接触到本地的磁盘。这意味着不能在本地磁盘上写和读,我们不想一个程序片通过WEB
页面阅读和传送重要的信息。写是被禁止的,当然,因为那将会引起病毒的侵入。当数字签名生效时,这些
限制会被解除。
(2) 程序片不能拥有菜单。(注意:这是规定在Swing 中的)这可能会减少关于安全和关于程序简化的麻
烦。我们可能会接到有关程序片协调利益以作为WEB 页面的一部分的通知;而我们通常不去注意程序片的范
围。这儿没有帧和标题条从菜单处弹出,出现的帧和标题条是属于WEB 浏览器的。也许将来设计能被改变成
允许我们将浏览器菜单和程序片菜单相结合起来——程序片可以影响它的环境将导致太危及整个系统的安全
并使程序片过于的复杂。
(3) 对话框是不被信任的。在Java 中,对话框存在一些令人难解的地方。首先,它们不能正确地拒绝程序
片,这实在是令人沮丧。如果我们从程序片弹出一个对话框,我们会在对话框上看到一个附上的消息框“不
被信任的程序片”。这是因为在理论上,它有可能欺骗用户去考虑他们在通过WEB 同一个老顾客的本地应用
程序交易并且让他们输入他们的信用卡号。在看到 AWT 开发的那种 GUI 后,我们可能会难过地相信任何人都
会被那种方法所愚弄。但程序片是一直附着在一个 Web 页面上的,并可以在浏览器中看到,而对话框没有这
种依附关系,所以理论上是可能的。因此,我们很少会见到一个使用对话框的程序片。
在较新的浏览器中,对受到信任的程序片来说,许多限制都被放宽了(受信任程序片由一个信任源认证)。
涉及程序片的开发时,还有另一些问题需要考虑:
■程序片不停地从一个适合不同类的单独的服务器上下载。我们的浏览器能够缓存程序片,但这没有保证。
在Java 1。1 版中的一个改进是 JAR (Java ARchive)文件,它允许将所有的程序片组件(包括其它的类文
件、图像、声音)一起打包到一个的能被单个服务器处理下载的压缩文件。“数字签字”(能校验类创建
器)可有效地加入每个单独的 JAR 文件。
■因为安全方面的缘故,我们做某些工作更加困难,例如访问数据库和发送电子邮件。另外,安全限制规则
使访问多个主机变得非常的困难,因为每一件事都必须通过WEB 服务器路由,形成一个性能瓶颈,并且单一
环节的出错都会导致整个处理的停止。
■浏览器里的程序片不会拥有同样的本地应用程序运行的控件类型。例如,自从用户可以开关页面以来,在
程序片中不会拥有一个形式上的对话框。当用户对一个WEB 页面进行改变或退出浏览器时,对我们的程序片
而言简直是一场灾难——这时没有办法保存状态,所以如果我们在处理和操作中时,信息会被丢失。另外,
当我们离开一个WEB 页面时,不同的浏览器会对我们的程序片做不同的操作,因此结果本来就是不确定的。
400
…………………………………………………………Page 402……………………………………………………………
13。14。1 程序片的优点
如果能容忍那些限制,那么程序片的一些优点也是非常突出的,尤其是在我们构建客户/服务器应用或者其
它网络应用时:
■没有安装方面的争议。程序片拥有真正的平台独立性(包括容易地播放声音文件等能力)所以我们不需要
针对不同的平台修改代码也不需要任何人根据安装运行任何的“tweaking ”。事实上,安装每次自动地将
WEB 页连同程序片一起,因此安静、自动地更新。在传统的客户机/服务器系统中,建立和安装一个新版本的
客户端软件简直就是一场恶梦。
■因为安全的原因创建在核心Java 语言和程序片结构中,我们不必担心坏的代码而导致毁坏某人的系统。这
样,连同前面的优点,可使用 Java (可从JavaScript 和VBScript 中选择客户端的WEB 编程工具)为所谓的
Intrant (在公司内部使用而不向Internet 转移的企业内部网络)客户机/服务器开发应用程序。
■由于程序片是自动同HTML 集成的,所以我们有一个内建的独立平台文件系统去支持程序片。这是一个很有
趣的方法,因为我们惯于拥有程序文件的一部分而不是相反的拥有文件系统。
13。15 视窗化应用
出于安全的缘故,我们会看到在程序片我们的行为非常的受到限制。我们真实地感到,程序片是被临时地加
入在WEB 浏览器中的,因此,它的功能连同它的相关知识,控件都必须加以限制。但是,我们希望Java 能制
造一个开窗口的程序去运行一些事物,否则宁愿安放在一个WEB 页面上,并且也许我们希望它可以运行一些
可靠的应用程序,以及夸张的实时便携性。在这本书前面的章节中我们制造了一些命令行应用程序,但在一
些操作环境中(例如:Macintosh)没有命令行。所以我们有很多的理由去利用Java 创建一个设置窗口,非
程序片的程序。这当然是一个十分合理的要求。
一个Java 设置窗口应用程序可以拥有菜单和对话框(这对一个程序片来说是不可能的和很困难的),可是如
果我们使用一个老版本的Java,我们将会牺牲本地操作系统环境的外观和感受。JFC/Swing 库允许我们制造
一个保持原来操作系统环境的外观和感受的应用程序。如果我们想建立一个设置窗口应用程序,它会合理地
运作,同样,如果我们可以使用最新版本的Java 并且集合所有的工具,我们就可以发布不会使用户困惑的应
用程序。如果因为一些原因,我们被迫使用老版本的Java,请在毁坏以建立重要的设置窗口的应用程序前仔
细地考虑。
13。15。1 菜单
直接在程序片中安放一个菜单是不可能的(Java 1。0;Java1。1 和 Swing 库不允许),因为它们是针对应用程
序的。继续,如果您不相信我并且确定在程序片中可以合理地拥有菜单,那么您可以去试验一下。程序片中
没有 setMenuBar()方法,而这种方法是附在菜单中的(我们会看到它可以合理地在程序片产生一个帧,并且
帧包含菜单)。
有四种不同类型的Menuponent (菜单组件),所有的菜单组件起源于抽象类:菜单条(我们可以在一个
事件帧里拥有一个菜单条),菜单去支配一个单独的下拉菜单或者子菜单、菜单项来说明菜单里一个单个的
元素,以及起源于MenuItem;产生检查标志(checkmark)去显示菜单项是否被选择的CheckBoxMenuItem。
不同的系统使用不同的资源,对Java 和 AWT 而言,我们必须在源代码中手工汇编所有的菜单。
//: Menu1。java
// Menus work only with Frames。
// Shows submenus; checkbox menu items
// and swapping menus。
import java。awt。*;
public class Menu1 extends Frame {
String'' flavors = { 〃Chocolate〃; 〃Strawberry〃;
〃Vanilla Fudge Swirl〃; 〃Mint Chip〃;
〃Mocha Almond Fudge〃; 〃Rum Raisin〃;
〃Praline Cream〃; 〃Mud Pie〃 };
TextField t = new TextField(〃No flavor〃; 30);
MenuBar mb1 = new MenuBar();
Menu f = new Menu(〃File〃);
401
…………………………………………………………Page 403……………………………………………………………
Menu m = new Menu(〃Flavors〃);
Menu s = new Menu(〃Safety〃);
// Alternative approach:
CheckboxMenuItem'' safety = {
new CheckboxMenuItem(〃Guard〃);
new CheckboxMenuItem(〃Hide〃)
};
MenuItem'' file = {
new MenuItem(〃Open〃);
new MenuItem(〃Exit〃)
};
// A second menu bar to swap to:
MenuBar mb2 = new MenuBar();
Menu fooBar = new Menu(〃fooBar〃);
MenuItem'' other = {
new MenuItem(〃Foo〃);
new MenuItem(〃Bar〃);
new MenuItem(〃Baz〃);
};
Button b = new Button(〃Swap Menus〃);
public Menu1() {
for(int i = 0; i 《 flavors。length; i++) {
m。add(new MenuItem(flavors'i'));
// Add separators at intervals:
if((i+1) % 3 == 0)
m。addSeparator();
}
for(int i = 0; i 《 safety。length; i++)
s。add(safety'i');
f。add(s);
for(int i = 0; i 《 file。length; i++)
f。add(file'i');
mb1。add(f);
mb1。add(m);
setMenuBar(mb1);
t。setEditable(false);
add(〃Center〃; t);
// Set up the system for swapping menus:
add(〃North〃; b);
for(int i = 0; i 《 other。length; i++)
fooBar。add(other'i');
mb2。add(fooBar);
}
public boolean handleEvent(Event evt) {
if(evt。id == Event。WINDOW_DESTROY)
System。exit(0);
else
return super。handleEvent(evt);
return true;
}
public boolean action(Event evt; Object arg) {
if(evt。target。equals(b)) {
402
…………………………………………………………Page 404……………………………………………………………
MenuBar m = getMenuBar();
if(m == mb1) setMenuBar(mb2);
else if (m == mb2) setMenuBar(mb1);
}
else if(evt。target instanceof MenuItem) {
if(arg。equals(〃Open〃)) {
String s = t。getText();
boolean chosen = false;
for(int i = 0; i 《 flavors。length; i++)
if(s。equals(flavors'i')) chosen = true;
if(!chosen)
t。setText(〃Choose a flavor first!〃);
else
t。setText(〃Opening 〃+ s +〃。 Mmm; mm!〃);
}
else if(evt。target。equals(file'1'))
System。exit(0);
// CheckboxMenuItems cannot use String
// matching; you must match the target:
else if(evt。target。equals(safety'0'))
t。setText(〃Guard the Ice Cream! 〃 +
〃Guarding is 〃 + safety'0'。getState());
else if(evt。target。equals(safety'1'))
t。setText(〃Hide the Ice Cream! 〃 +
〃Is it cold? 〃 + safety'1'。getState());
else
t。setText(arg。toString());
}
else
return super。action(evt; arg);
return true;
}
public static void main(String'' args) {
Menu1 f = new Menu1();
f。resize(300;200);
f。show();
}
} ///:~
在这个程序中,我避免了为每个菜单编写典型的冗长的add()列表调用,因为那看起来像许多的无用的标
志。取而代之的是,我安放菜单项到数组中,然后在一个 for 的循环中通过每个数组调用add()简单地跳
过。这样的话,增加和减少菜单项变得没那么讨厌了。
作为一个可选择的方法(我发现这很难令我满意,因为它需要更多的分配)CheckboxMenuItems 在数组的句
柄中被创建是被称为安全创建;这对数组文件和其它的文件而言是真正的安全。
程序中创建了不是一个而是二个的菜单条来证明菜单条在程序运行时能被交换激活。我们可以看到菜单条怎
样组成菜单,每个菜单怎样组成菜单项(MenuItems),chenkboxMenuItems 或者其它的菜单(产生
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!