友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
Java编程思想第4版[中文版](PDF格式)-第81部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
单击在BangBean 上时会被激活的接收器。这样,我们将能够确认可支持的属性和事件:
//: BangBean。java
// A graphical Bean
package bangbean;
import java。awt。*;
import java。awt。event。*;
import java。io。*;
import java。util。*;
public class BangBean extends Canvas
implements Serializable {
protected int xm; ym;
protected int cSize = 20; // Circle size
protected String text = 〃Bang!〃;
protected int fontSize = 48;
protected Color tColor = Color。red;
protected ActionListener actionListener;
public BangBean() {
addMouseListener(new ML());
addMouseMotionListener(new MML());
}
public int getCircleSize() { return cSize; }
public void setCircleSize(int newSize) {
cSize = newSize;
}
public String getBangText() { return text; }
public void setBangText(String newText) {
text = newText;
}
public int getFontSize() { return fontSize; }
public void setFontSize(int newSize) {
fontSize = newSize;
}
public Color getTextColor() { return tColor; }
public void setTextColor(Color newColor) {
tColor = newColor;
}
public void paint(Graphics g) {
g。setColor(Color。black);
g。drawOval(xm cSize/2; ym cSize/2;
cSize; cSize);
}
// This is a unicast listener; which is
// the simplest form of listener management:
public void addActionListener (
ActionListener l)
463
…………………………………………………………Page 465……………………………………………………………
throws TooManyListenersException {
if(actionListener != null)
throw new TooManyListenersException();
actionListener = l;
}
public void removeActionListener(
ActionListener l) {
actionListener = null;
}
class ML extends MouseAdapter {
public void mousePressed(MouseEvent e) {
Graphics g = getGraphics();
g。setColor(tColor);
g。setFont(
new Font(
〃TimesRoman〃; Font。BOLD; fontSize));
int width =
g。getFontMetrics()。stringWidth(text);
g。drawString(text;
(getSize()。width width) /2;
getSize()。height/2);
g。dispose();
// Call the listener's method:
if(actionListener != null)
actionListener。actionPerformed(
new ActionEvent(BangBean。this;
ActionEvent。ACTION_PERFORMED; null));
}
}
class MML extends MouseMotionAdapter {
public void mouseMoved(MouseEvent e) {
xm = e。getX();
ym = e。getY();
repaint();
}
}
public Dimension getPreferredSize() {
return new Dimension(200; 200);
}
// Testing the BangBean:
public static void main(String'' args) {
BangBean bb = new BangBean();
try {
bb。addActionListener(new BBL());
} catch(TooManyListenersException e) {}
Frame aFrame = new Frame(〃BangBean Test〃);
aFrame。addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System。exit(0);
}
});
464
…………………………………………………………Page 466……………………………………………………………
aFrame。add(bb; BorderLayout。CENTER);
aFrame。setSize(300;300);
aFrame。setVisible(true);
}
// During testing; send action information
// to the console:
static class BBL implements ActionListener {
public void actionPerformed(ActionEvent e) {
System。out。println(〃BangBean action〃);
}
}
} ///:~
最重要的是我们会注意到BangBean 执行了这种串联化的接口。这意味着应用程序构建工具可以在程序设计者
调整完属性值后利用串联为BangBean 贮藏所有的信息。当Bean 作为运行的应用程序的一部分被创建时,那
些被贮藏的属性被重新恢复,因此我们可以正确地得到我们的设计。
我们能看到通常同Bean 一起运行的所有的字段都是专用的——允许只能通过方法来访问,通常利用“属性”
结构。
当我们注视着addActionListener()的签名时,我们会注意到它可以产生出一个TooManyListenerException
(太多接收器异常)。这个异常指明它是一个单一的类型的,意味着当事件发生时,它只能通知一个接收
器。一般情况下,我们会使用具有多种类型的事件,以便一个事件通知多个的接收器。但是,那样会陷入直
到下一章我们才能准备好的结局中,因此这些内容会被重新回顾(下一个标题是“Java Beans 的重新回
顾”)。单一类型的事件回避了这个难题。
当我们按下鼠标键时,文字被安入 BangBean 中间,并且如果动作接收器字段存在,它的actionPerformed()
方法就被调用,创建一个新的ActionEvent 对象在处理过程中。无论何时鼠标移动,它的新座标将被捕捉,
并且画布会被重画(像我们所看到的抹去一些画布上的文字)。
main()方法增加了允许我们从命令行中测试程序的功能。当一个 Bean 在一个开发环境中,main()方法不会被
使用,但拥有它是绝对有益的,因为它提供了快捷的测试能力。无论何时一个ActionEvent 发生,main()方
法都将创建了一个帧并安置了一个 BangBean 在它里面,还在BangBean 中附上了一个简单的动作接收器以打
印到控制台。当然,一般来说应用程序构建工具将创建大多数的Bean 的代码。当我们通过BeanDumper 或者
安放BangBean 到一个可激活Bean 的开发环境中去运行BangBean 时,我们会注意到会有很多额外的属性和动
作明显超过了上面的代码。那是因为BangBean 从画布中继承,并且画布就是一个 Bean ,因此我们看到它的
属性和事件同样的合适。
13。18。4 Bean 的封装
在我们可以安放一个Bean 到一个可激活Bean 的可视化构建工具中前,它必须被放入到标准的Bean 容器里,
也就是包含 Bean 类和一个表示“这是一个Bean ”的清单文件的JAR (Java ARchive,Java 文件)文件中。
清单文件是一个简单的紧随事件结构的文本文件。对于BangBean 而言,清单文件就像下面这样:
Manifest…Version: 1。0
Name: bangbean/BangBean。class
Java…Bean: True
其中,第一行指出清单文件结构的版本,这是 SUN 公司在很久以前公布的版本。第二行(空行忽略)对文件
命名为BangBean。class。第三行表示“这个文件是一个Bean ”。没有第三行,程序构建工具不会将类作为一
个Bean 来认可。
唯一难以处理的部分是我们必须肯定“Name:”字段中的路径是正确的。如果我们回顾BangBean。java ,我们
会看到它在 package bangbean (因为存放类路径的子目录称为“bangbean ”)中,并且这个名字在清单文件
中必须包括封装的信息。另外,我们必须安放清单文件在我们封装路径的根目录上,在这个例子中意味着安
放文件在bangbean 子目录中。这之后,我们必须从同一目录中调用 Jar 来作为清单文件,如下所示:
jar cfm BangBean。jar BangBean。mf bangbean
465
…………………………………………………………Page 467……………………………………………………………
这个例子假定我们想产生一个名为 BangBean。jar 的文件并且我们将清单放到一个称为BangBean。mf 文件中。
我们可能会想“当我编译BangBean。java 时,产生的其它类会怎么样呢?”哦,它们会在bangbean 子目录中
被中止,并且我们会注意到上面jar命令行的最后一个自变量就是 bangbean 子目录。当我们给 jar子目录名
时,它封装整个的子目录到jar文件中(在这个例子中,包括 BangBean。java 的源代码文件——对于我们自
己的Bean 我们可能不会去选择包含源代码文件。)另外,如果我们改变主意,解开打包的 JAR 文件,我们会
发现我们清单文件并不在里面,但jar创建了它自己的清单文件(部分根据我们的文件),称为
MAINFEST。MF 并且安放它到META…INF子目录中(代表“meta…information”)。如果我们打开这个清单文
件,我们同样会注意到 jar为每个文件加入数字签名信息,其结构如下:
Digest…Algorithms: SHA MD5
SHA…Digest: pDpEAG9NaeCx8aFtqPI4udSX/O0=
MD5…Digest: O4NcS1hE3Smnzlp2hj6qeg==
一般来说,我们不必担心这些,如果我们要做一些修改,可以修改我们的原始的清单文件并且重新调用jar
以为我们的Bean 创建了一个新的JAR 文件。我们同样也可以简单地通过增加其它的 Bean 的信息到我们清单
文件来增加它们到 JAR 文件中。
值得注意的是我们或许需要安放每个Bean 到它自己的子目录中,因为当我们创建一个JAR 文件时,分配JAR
应用目录名并且JAR 放置子目录中的任何文件到JAR 文件中。我们可以看到 Frog 和 BangBean 都在它们自己
的子目录中。
一旦我们将我们的Bean 正确地放入一个 JAR 文件中,我们就可以携带它到一个可以激活Bean 的编程环境中
使用。使用这种方法,我们可以从一种工具到另一种工具间交替变换,但 SUN 公司为 Java Beans 提供了免费
高效的测试工具在它们的“Bean Development Kit,Bean 开发工具”(BDK)称为“beanbox”。(我们可以
从javasoft。 处下载。)在我们启动 beanbox 前,放置我们的Bean 到beanbox 中,复制JAR 文件到
BDK 的“jars”子目录中。
13。18。5 更复杂的 Bean 支持
我们可以看到创建一个 Bean 显然多么的简单。在程序设计中我们几乎不受到任何的限制。Java Bean 的设计
提供了一个简单的输入点,这样可以提高到更复杂的层次上。这些高层次的问题超出了这本书所要讨论的范
围,但它们会在此做简要的介绍。我们可以在 http://java。sun。/beans 上找到更多的详细资料。
我们增加更加复杂的程序和它的属性到一个位置。上面的例子显示一个独特的属性,当然它也可能代表一个
数组的属性。这称为索引属性。我们简单地提供一个相应的方法(再者有一个方法名的命名规则)并且
Introspector认可索引属性,因此我们的应用程序构建工具相应的处理。
属性可以被捆绑,这意味着它们将通过 PropertyChangeEvent 通知其它的对象。其它的对象可以随后根据对
Bean 的改变选择修改它们自己。
属性可以被束缚,这意味着其它的对象可以在一个属性的改变不能被接受时,拒绝它。其它的对象利用一个
PropertyChangeEvent 来通知,并且它们产生一个ProptertyVetoException 去阻止修改的发生,并恢复为原
来的值。
我们同样能够改变我们的Bean 在设计时的被描绘成的方法:
(1) 我们可以为我们特殊的 Bean 提供一个定制的属性表。这个普通的属性表将被所有的Bean 所使用,但当
我们的Bean 被选择时,它会自动地调用这张属性表。
(2) 我们可以为一个特殊的属性创建一个定制的编辑器,因此普通的属性表被使用,但当我们指定的属性被
调用时,编辑器会自动地被调用。
(3)我们可以为我们的 Bean 提供一个定制的BeanInfo 类,产生的信息不同于由 Introspector 默认产生的。
(4) 它同样可能在所有的FeatureDescriptors 中改变“expert”的开关模式,以辨别基本特征和更复杂的特
征。
13。18。6 Bean 更多的知识
另外有关的争议是Bean 不能被编址。无论何时我们创建一个Bean ,都希望它会在一个多线程的环境中运
行。这意味着我们必须理解线程的出口,我们将在下一章中介绍。我们会发现有一段称为“Java Beans 的回
顾”的节会注意到这个问题和它的解决方案。
466
…………………………………………………………Page 468……………………………………………………………
13。19 Swing 入门(注释⑦)
通过这一章的学习,当我们的工作方法在AWT 中发生了巨大的改变后(如果可以回忆起很久以前,当Java 第
一次面世时 SUN 公司曾声明 Java 是一种“稳定,牢固”的编程语言),可能一直有 Java 还不十分的成熟的
感觉。的确,现在 Java 拥有一个不错的事件模型以及一个优秀的组件复用设计——JavaBeans。但GUI 组件
看起来还相当的原始,笨拙以及相当的抽象。
⑦:写作本节时,Swing 库显然已被 Sun “固定”下来了,所以只要你下载并安装了Swing 库,就应该能正确
地编译和运行这里的代码,不会出现任何问题(应该能编译Sun 配套提供的演示程序,以检测安装是否正
确)。若遇到任何麻烦,请访问http://BruceEckel。,了解最近的更新情况。
而这就是Swing 将要占领的领域。Swing 库在 Java 1。1 之后面世,因此我们可以自然而然地假设它是 Java
1。2 的一部分。可是,它是设计为作为一个补充在 Java 1。1 版中工作的。这样,我们就不必为了享用好的 UI
组件库而等待我们的平台去支持Java 1。2 版了。如果 Swing 库不是我们的用户的Java 1。1 版所支持的一部
分,并且产生一些意外,那他就可能真正的需要去下载Swing 库了。
Swing 包含所有我们缺乏的组件,在整个本章余下的部分中:我们期望领会现代化的UI,来自按钮的任何事
件包括到树状和网格结构中的图片。它是一个大库,但在某些方面它为任务被设计得相应的复杂——如果任
何事都是简单的,我们不必编写更多的代码但同样设法运行我们的代码逐渐地变得更加的复杂。这意味着一
个容易的入口,如果我们需要它我们得到它的强大力量。
Swing 相当的深奥,这一节不会去试图让读者理解,但会介绍它的能力和Swing 简单地使我们着手使用库。
请注意我们有意识的使用这一切变得简单。如果我们需要运行更多的,这时Swing 能或许能给我们所想要
的,如果我们愿意深入地研究,可以从SUN 公司的在线文档中获取更多的资料。
13。19。1 Swing 有哪些优点
当我们开始使用Swing 库时,会注意到它在技术上向前迈出了巨大的一步。Swing 组件是 Bean ,因此他们可
以支持Bean 的任何开发环境中使用。Swing 提供了一个完全的UI 组件集合。因为速度的关系,所有的组件
都很小巧的(没有“重量级”组件被使用),Swing 为了轻便在 Java 中整个被编写。
最重要的是我们会希望 Swing 被称为“正交使用”;一旦我们采用了这种关于库的普遍的办法我们就可以在
任何地方应用它们。这主要是因为 Bean 的命名规则,大多数的时候在我编写这些程序例子时我可以猜到方法
名并且第一次就将它拼写正确而无需查找任何事物。这无疑是优秀库设计的品质证明。另外,我们可以广泛
地插入组件到其它的组件中并且事件会正常地工作。
键盘操作是自动被支持的——我们可以使用 Swing 应用程序而不需要鼠标,但我们不得不做一些额外的编程
工作(老的 AWT 中需要一些可怕的代码以支持键盘操作)。滚动被毫不费力地支持——我们简单地将我们的
组件到一个 JScrollPane 中,同样我们再增加它到我们的窗体中即可。其它的特征,例如工具提示条只需要
一行单独的代码就可执行。
Swing 同样支持一些被称为“可插入外观和效果”的事物,这就是说UI 的外观可以在不同的平台和不同的操
作系统上被动态地改变以符合用户的期望。它甚至可以创造我们自己的外观和效果。
13。19。2 方便的转换
如果我们长期艰苦不懈地利用 Java 1。1 版构建我们的UI,我们并不需要扔掉它改变到Swing 阵营中来。幸
运的是,库被设计得允许容易地修改——在很多情况下我们可以简单地放一个“J”到我们老AWT 组件的每个
类名前面即可。下面这个例子拥有我们所熟悉的特色:
//: JButtonDemo。java
// Looks like Java 1。1 but with J's added
package c13。swing;
import java。awt。*;
import java。awt。event。*;
import java。applet。*;
import javax。swing。*;
public class JButtonDemo extends Applet {
467
…………………………………………………………Page 469……………………………………………………………
JButton
b1 = new JButton(〃JButton 1〃);
b2 = new JButton(〃JButton 2〃);
JTextField t = new JTextField(20);
public void init() {
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e){
String name =
((JButton)e。getSource())。getText();
t。setText(name + 〃 Pressed〃);
}
};
b1。addActionListener(al);
add(b1);
b2。addActionListener(al);
add(b2);
add(t);
}
public static void main(String args'') {
JButtonDemo applet = new JButtonDemo();
JFrame frame = new JFrame(〃TextAreaNew〃);
frame。addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
System。exit(0);
}
});
frame。getContentPane()。add(
applet; BorderLayout。CENTER);
frame。setSize(300;100);
applet。init();
applet。start();
frame。setVisible(true);
}
} ///:~
这是一个新的输入语句,但此外任何事物除了增加了一些“J”外,看起都像这 Java 1。1 版的AWT。同样,
我们不恰当的用add()方法增加到 Swing JFrame 中,除此之外我们必须像上面看到的一样先准备一些
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!