Java编程思想第4版[中文版](PDF格式)-第119部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
454
…………………………………………………………Page 456……………………………………………………………
import java。awt。datatransfer。*;
public class CutAndPaste extends Frame {
MenuBar mb = new MenuBar();
Menu edit = new Menu(〃Edit〃);
MenuItem
cut = new MenuItem(〃Cut〃);
copy = new MenuItem(〃Copy〃);
paste = new MenuItem(〃Paste〃);
TextArea text = new TextArea(20;20);
Clipboard clipbd =
getToolkit()。getSystemClipboard();
public CutAndPaste() {
cut。addActionListener(new CutL());
copy。addActionListener(new CopyL());
paste。addActionListener(new PasteL());
edit。add(cut);
edit。add(copy);
edit。add(paste);
mb。add(edit);
setMenuBar(mb);
add(text; BorderLayout。CENTER);
}
class CopyL implements ActionListener {
public void actionPerformed(ActionEvent e) {
String selection = text。getSelectedText();
StringSelection clipString =
new StringSelection(selection);
clipbd。setContents(clipString; clipString);
}
}
class CutL implements ActionListener {
public void actionPerformed(ActionEvent e) {
String selection = text。getSelectedText();
StringSelection clipString =
new StringSelection(selection);
clipbd。setContents(clipString; clipString);
text。replaceRange(〃〃;
text。getSelectionStart();
text。getSelectionEnd());
}
}
class PasteL implements ActionListener {
public void actionPerformed(ActionEvent e) {
Transferable clipData =
clipbd。getContents(CutAndPaste。this);
try {
String clipString =
(String)clipData。
getTransferData(
DataFlavor。stringFlavor);
text。replaceRange(clipString;
455
…………………………………………………………Page 457……………………………………………………………
text。getSelectionStart();
text。getSelectionEnd());
} catch(Exception ex) {
System。out。println(〃not String flavor〃);
}
}
}
public static void main(String'' args) {
CutAndPaste cp = new CutAndPaste();
cp。addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System。exit(0);
}
});
cp。setSize(300;200);
cp。setVisible(true);
}
} ///:~
创建和增加菜单及 TextArea 到如今似乎已变成一种单调的活动。这与通过工具组件创建的剪贴板字段
clipbd有很大的区别。
所有的动作都安置在接收器中。CopyL 和Cupl 接收器同样除了最后的 CutL 线以外删除被复制的线。特殊的
两条线是StringSelection 对象从字符串从创建并调用StringSelection 的 setContents()方法。说得更准
确些,就是放一个字符串到剪切板上。
在PasteL 中,数据被剪贴板利用 getContents()进行分解。任何返回的对象都是可移动的匿名的,并且我们
并不真正地知道它里面包含了什么。有一种发现的方法是调用 getTransferDateFlavors(),返回一个
DataFlavor 对象数组,表明特殊对象支持这种特点。我们同样能要求它通过我们感兴趣的特点直接地使用
IsDataFlavorSupported()。但是在这里使用一种大胆的方法:调用getTransferData ( )方法,假设里面
的内容支持字符串特色,并且它不是个被分类在异常处理器中的难题 。
在将来,我们希望更多的数据特色能够被支持。
13。18 可视编程和 Beans
迄今为止,我们已看到 Java 对创建可重复使用的代码片工作而言是多么的有价值。“最大限度地可重复使
用”的代码单元拥有类,因为它包含一个紧密结合在一起的单元特性(字段)和单元动作(方法),它们可
以直接经过混合或通过继承被重复使用。
继承和多形态性是面向对象编程的精华,但在大多数情况下当我们创建一个应用程序时,我们真正最想要的
恰恰是我们最需要的组件。我们希望在我们的设计中设置这些部件就像电子工程师在电路板上创造集成电路
块一样(在使用Java 的情况下,就是放到WEB 页面上)。这似乎会成为加快这种“模块集合”编制程序方法
的发展。
“可视化编程”最早的成功——非常的成功——要归功于微软公司的Visual Basic (VB,可视化Basic 语
言),接下来的第二代是Borland 公司Delphi (一种客户/服务器数据库应用程序开发工具,也是Java
Beans 设计的主要灵感)。这些编程工具的组件的像征就是可视化,这是不容置疑的,因为它们通常展示一
些类型的可视化组件,例如:一个按惯或一个 TextField。事实上,可视化通常表现为组件可以非常精确地
访问运行中程序。因此可视化编程方法的一部分包含从一个调色盘从拖放一个组件并将它放置到我们的窗体
中。应用程序创建工具像我们所做的一样编写程序代码,该代码将导致正在运行的程序中的组件被创建。
简单地拖放组件到一个窗体中通常不足以构成一个完整的程序。一般情况下,我们需要改变组件的特性,例
如组件的色彩,组件的文字,组件连结的数据库,等等。特性可以参照属性在编程时进行修改。我们可以在
应用程序构建工具中巧妙处置我们组件的属性,并且当我们创建程序时,构建数据被保存下来,所以当该程
序被启动时,数据能被重新恢复。
到如今,我们可能习惯于使用对象的多个特性,这也是一个动作集合。在设计时,可视化组件的动作可由事
件部分地代表,意味着“任何事件都可以发生在组件上”。通常,由我们决定想发生的事件,当一个事件发
456
…………………………………………………………Page 458……………………………………………………………
生时,对所发生的事件连接代码。
这是关键性的部分:应用程序构建工具可以动态地询问组件(利用映象)以发现组件支持的事件和属件。一
旦它知道它们的状态,应用程序构建工具就可以显示组件的属性并允许我们修改它们的属性(当我们构建程
序时,保存它们的状态),并且也显示这些事件。一般而言,我们做一些事件像双击一个事件以及应用程序
构建工具创建一个代码并连接到事件上。当事件发生时,我们不得不编写执行代码。应用程序构建工具累计
为我们做了大量的工作。结果我们可以注意到程序看起来像它所假定的那样运行,并且依赖应用程序构建工
具去为我们管理连接的详细资料。可视化的编程工具如此成功的原因是它们明显加快构建的应用程序的处理
过程——当然,用户接口作为应用程序的一部分同样的好。
13。18。1 什么是 Bean
在经细节处理后,一个组件在类中被独特的具体化,真正地成为一块代码。关键的争议在于应用程序构建工
具发现组件的属性和事件能力。为了创建一个 VB 组件,程序开发者不得不编写正确的同时也是复杂烦琐的代
码片,接下来由某些协议去展现它们的事件和属性。Delphi 是第二代的可视化编程工具并且这种开发语言主
动地围绕可视化编程来设计因此它更容易去创建一个可视化组件。但是,Java 带来了可视化的创作组件做为
Java Beans 最高级的“装备”,因为一个 Bean 就是一个类。我们不必再为制造任何的Bean 而编写一些特殊
的代码或者使用特殊的编程语言。事实上,我们唯一需要做的是略微地修改我们对我们方法命名的办法。方
法名通知应用程序构建工具是否是一个属性,一个事件或是一个普通的方法。
在Java 的文件中,命名规则被错误地曲解为“设计范式”。这十分的不幸,因为设计范式(参见第 16章)
惹来不少的麻烦。命名规则不是设计范式,它是相当的简单:
(1) 因为属性被命名为 xxx,我们代表性的创建两个方法:getXxx()和 setXxx()。注意 get 或 set后的第一
个字母小写以产生属性名。“get”和“set”方法产生同样类型的自变量。“set”和“get”的属性名和类
型名之间没有关系。
(2) 对于布尔逻辑型属性,我们可以使用上面的“get”和“set”方法,但我们也可以用“is”代替
“ get ”。
(3) Bean 的普通方法不适合上面的命名规则,但它们是公用的。
4。对于事件,我们使用“listener (接收器)”方法。这种方法完全同我们看到过的方法相同:
(addFooBarListener(FooBarListener)和 removeFooBarListener(FooBarListener)方法用来处理 FooBar 事
件。大多数时候内建的事件和接收器会满足我们的需要,但我们可以创建自己的事件和接收器接口。
上面的第一点回答了一个关于我们可能注意到的从 Java 1。0 到Java 1。1 的改变的问题:一些方法的名字太
过于短小,显然改写名字毫无意义。现在我们可以看到为了制造Bean 中的特殊的组件,大多数的这些修改不
得不适合于“get”和“set”命名规则。
现在,我们已经可以利用上面的这些指导方针去创建一个简单的Bean :
//: Frog。java
// A trivial Java Bean
package frogbean;
import java。awt。*;
import java。awt。event。*;
class Spots {}
public class Frog {
private int jumps;
private Color color;
private Spots spots;
private boolean jmpr;
public int getJumps() { return jumps; }
public void setJumps(int newJumps) {
jumps = newJumps;
}
public Color getColor() { return color; }
public void setColor(Color newColor) {
457
…………………………………………………………Page 459……………………………………………………………
color = newColor;
}
public Spots getSpots() { return spots; }
public void setSpots(Spots newSpots) {
spots = newSpots;
}
public boolean isJumper() { return jmpr; }
public void setJumper(boolean j) { jmpr = j; }
public void addActionListener(
ActionListener l) {
//。。。
}
public void removeActionListener(
ActionListener l) {
// 。。。
}
public void addKeyListener(KeyListener l) {
// 。。。
}
public void removeKeyListener(KeyL istener l) {
// 。。。
}
// An 〃ordinary〃 public method:
public void croak() {
System。out。println(〃Ribbet!〃);
}
} ///:~
首先,我们可看到Bean 就是一个类。通常,所有我们的字段会被作为专用,并且可以接近的唯一办法是通过
方法。紧接着的是命名规则,属性是jump,color,jumper,spots (注意这些修改是在第一个字母在属性名
的情况下进行的)。虽然内部确定的名字同最早的三个例子的属性名一样,在jumper 中我们可以看到属性名
不会强迫我们使用任何特殊的内部可变的名字(或者,真的拥有一些内部的可变的属性名)。
Bean 事件的句柄是ActionEvent 和KeyEvent ,这是根据有关接收器的“add”和“remove”命名方法得出
的。最后我们可以注意到普通的方法croak()一直是Bean 的一部分,仅仅是因为它是一个公共的方法,而不
是因为它符合一些命名规则。
13。18。2 用 Introspector 提取 BeanInfo
当我们拖放一个Bean 的调色板并将它放入到窗体中时,一个Bean 的最关键的部分的规则发生了。应用程序
构建工具必须可以创建 Bean (如果它是默认的构建器的话,它就可以做)然后,在此范围外访问Bean 的源