友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
Java编程思想第4版[中文版](PDF格式)-第70部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
add(t);
add(lst);
add(b);
}
public boolean handleEvent(Event evt) {
if(evt。id == Event。LIST_SELECT ||
evt。id == Event。LIST_DESELECT) {
if(evt。target。equals(lst)) {
t。setText(〃〃);
String'' items = lst。getSelectedItems();
for(int i = 0; i 《 items。length; i++)
t。appendText(items'i' + 〃n〃);
}
else
return super。handleEvent(evt);
}
else
return super。handleEvent(evt);
return true;
}
public boolean action(Event evt; Object arg) {
if(evt。target。equals(b)) {
if(count 《 flavors。length)
lst。addItem(flavors'count++'; 0);
}
else
return super。action(evt; arg);
return true;
}
} ///:~
这个例子同前面的例子相同除了增加了handleEvent()外简直一模一样。在程序中做了试验来验证是否列表
框的选择和非选择存在。现在请记住,handleEvent()被程序片所过载,所以它能在窗体中任何存在,并且被
其它的列表当成事件来处理。因此我们同样必须通过试验来观察目标。(虽然在这个例子中,程序片中只有
一个列表框所以我们能假设所有的列表框事件必须服务于列表框。这是一个不好的习惯,一旦其它的列表框
加入,它就会变成程序中的一个缺陷。)如果列表框匹配一个我们感兴趣的列表框,像前面的一样的代码将
按上面的策略来运行。注意handleEvent() 的窗体与action()的相同:如果我们处理一个单独的事件,将返
回真值,但如果我们对其它的一些事件不感兴趣,通过handleEvent()我们必须返回 super。handleEvent()
值。这便是程序的核心,如果我们不那样做,其它的任何一个事件处理代码也不会被调用。例如,试注解在
392
…………………………………………………………Page 394……………………………………………………………
上面的代码中返回 super。handleEvent(evt) 的值。我们将发现action() 没有被调用,当然那不是我们想得到
的。对action()和handlEvent()而言,最重要的是跟着上面例子中的格式,并且当我们自己不处理事件时一
直返回基础类的方法版本信息。(在例子中我们将返回真值)。(幸运的是,这些类型的错误的仅属于 Java
1。0版,在本章后面将看到的新设计的 Java 1。1 消除了这些类型的错误。)
在windows 里,如果我们按下 shift 键,列表框自动允许我们做多个选择。这非常的棒,因为它允许用户做
单个或多个的选择而不是编程期间固定的。我们可能会认为我们变得更加的精明,并且当一个鼠标单击被
evt。shiftdown()产生时如果 shift 键是按下的将执行我们自己的试验程序。AWT 的设计妨碍了我们-我们不
得不去了解哪个项目被鼠标点击时是否按下了 shift键,所以我们能取消其余部分所有的选择并且只选择那
一个。不管怎样,我们是不可能在 Java 1。0 版中做出来的。(Java 1。1 将所有的鼠标、键盘、焦点事件传
送到列表中,所以我们能够完成它。)
13。12 布局的控制
在Java 里该方法是安一个组件到一个窗体中去,它不同我们使用过的其它GUI 系统。首先,它是全代码的;
没有控制安放组件的“资源”。其次,该方法的组件被安放到一个被“布局管理器”控制的窗体中,由“布
局管理器”根据我们add()它们的决定来安放组件。大小,形状,组件位置与其它系统的布局管理器显著的
不同。另外,布局管理器使我们的程序片或应用程序适合窗口的大小,所以,如果窗口的尺寸改变(例如,
在HTML 页面的程序片指定的规格),组件的大小,形状和位置都会改变。
程序片和帧类都是来源于包含和显示组件的容器。(这个容器也是一个组件,所以它也能响应事件。)在容
器中,调用 setLayout()方法允许我选择不同的布局管理器。
在这节里我们将探索不同的布局管理器,并安放按钮在它们之上。这里没有捕捉按钮的事件,正好可以演示
如何布置这些按钮。
13。12。1 FlowLayout
到目前为止,所有的程序片都被建立,看起来使用一些不可思议的内部逻辑来布置它们的组件。那是因为程
序使用一个默认的方式:FlowLayout。这个简单的“Flow ”的组件安装在窗体中,从左到右,直到顶部的空
格全部再移去一行,并继续循环这些组件。
这里有一个例子明确地(当然也是多余地)设置一个程序片的布局管理器去FlowLayout,然后在窗体中安放
按钮。我们将注意到FlowLayout 组件使用它们本来的大小。例如一个按钮将会变得和它的字串符一样的大
小。
//: FlowLayout1。java
// Demonstrating the FlowLayout
import java。awt。*;
import java。applet。*;
public class FlowLayout1 extends Applet {
public void init() {
setLayout(new FlowLayout());
for(int i = 0; i 《 20; i++)
add(new Button(〃Button 〃 + i));
}
} ///:~
所有组件将在FlowLayout 中被压缩为它们的最小尺寸,所以我们可能会得到一些奇怪的状态。例如,一个标
签会合适它自已的字符串的尺寸,所以它会右对齐产生一个不变的显示。
13。12。2 BorderLayout
布局管理器有四边和中间区域的概念。当我们增加一些事物到使用 BorderLayout 的面板上时我们必须使用
add()方法将一个字符串对象作为它的第一个自变量,并且字符串必须指定(正确的大写)“North”
(上),“South”(下),“west ”(左),“East ”(右)或者“Center”。如果我们拼写错误或没有大
写,就会得到一个编译时的错误,并且程序片不会像你所期望的那样运行。幸运的是,我们会很快发现在
393
…………………………………………………………Page 395……………………………………………………………
Java 1。1 中有了更多改进。
这是一个简单的程序例子:
//: BorderLayout1。java
// Demonstrating the BorderLayout
import java。awt。*;
import java。applet。*;
public class BorderLayout1 extends Applet {
public void init() {
int i = 0;
setLayout(new BorderLayout());
add(〃North〃; new Button(〃Button 〃 + i++));
add(〃South〃; new Button(〃Button 〃 + i++));
add(〃East〃; new Button(〃Button 〃 + i++));
add(〃West〃; new Button(〃Button 〃 + i++));
add(〃Center〃; new Button(〃Button 〃 + i++));
}
} ///:~
除了“Center”的每一个位置,当元素在其它空间内扩大到最大时,我们会把它压缩到适合空间的最小尺
寸。但是,“Center”扩大后只会占据中心位置。
BorderLayout 是应用程序和对话框的默认布局管理器。
13。12。3 GridLayout
GridLayout 允许我们建立一个组件表。添加那些组件时,它们会按从左到右、从上到下的顺序在网格中排
列。在构建器里,需要指定自己希望的行、列数,它们将按正比例展开。
//: GridLayout1。java
// Demonstrating the GridLayout
import java。awt。*;
import java。applet。*;
public class GridLayout1 extends Applet {
public void init() {
setLayout(new GridLayout(7;3));
for(int i = 0; i 《 20; i++)
add(new Button(〃Button 〃 + i));
}
} ///:~
在这个例子里共有 21 个空位,但却只有 20 个按钮,最后的一个位置作留空处理;注意对GridLayout 来说,
并不存在什么“均衡”处理。
13。12。4 CardLayout
CardLayout 允许我们在更复杂的拥有真正的文件夹卡片与一条边相遇的环境里创建大致相同于“卡片式对话
框”的布局,我们必须压下一个卡片使不同的对话框带到前面来。在 AWT 里不是这样的:CardLayout 是简单
的空的空格,我们可以自由地把新卡片带到前面来。(JFC/Swing 库包括卡片式的窗格看起来非常的棒,且
可以我们处理所有的细节。)
1。 联合布局(bining layouts)
394
…………………………………………………………Page 396……………………………………………………………
下面的例子联合了更多的布局类型,在最初只有一个布局管理器被程序片或应用程序操作看起来相当的困
难。这是事实,但如果我们创建更多的面板对象,每个面板都能拥有一个布局管理器,并且像被集成到程序
片或应用程序中一样使用程序片或应用程序的布局管理器。这就象下面程序中的一样给了我们更多的灵活
性:
//: CardLayout1。java
// Demonstrating the CardLayout
import java。awt。*;
import java。applet。Applet;
class ButtonPanel extends Panel {
ButtonPanel(String id) {
setLayout(new BorderLayout());
add(〃Center〃; new Button(id));
}
}
public class CardLayout1 extends Applet {
Button
first = new Button(〃First〃);
second = new Button(〃Second〃);
third = new Button(〃Third〃);
Panel cards = new Panel();
CardLayout cl = new CardLayout();
public void init() {
setLayout(new BorderLayout());
Panel p = new Panel();
p。setLayout(new FlowLayout());
p。add(first);
p。add(second);
p。add(third);
add(〃North〃; p);
cards。setLayout(cl);
cards。add(〃First card〃;
new ButtonPanel(〃The first one〃));
cards。add(〃Second card〃;
new ButtonPanel(〃The second one〃));
cards。add(〃Third card〃;
new ButtonPanel(〃The third one〃));
add(〃Center〃; cards);
}
public boolean action(Event evt; Object arg) {
if (evt。target。equals(first)) {
cl。first(cards);
}
else if (evt。target。equals(second)) {
cl。first(cards);
cl。next(cards);
}
else if (evt。target。equals(third)) {
cl。last(cards);
}
395
…………………………………………………………Page 397……………………………………………………………
else
return super。action(evt; arg);
return true;
}
} ///:~
这个例子首先会创建一种新类型的面板:BottonPanel (按钮面板)。它包括一个单独的按钮,安放在
BorderLayout 的中央,那意味着它将充满整个的面板。按钮上的标签将让我们知道我们在CardLayout 上的
那个面板上。
在程序片里,面板卡片上将存放卡片和布局管理器 CL 因为CardLayout 必须组成类,因为当我们需要处理卡
片时我们需要访问这些句柄。
这个程序片变成使用BorderLayout 来取代它的默认FlowLayout,创建面板来容纳三个按钮(使用
FlowLayout),并且这个面板安置在程序片末尾的“North”。卡片面板增加到程序片的“Center”里,有效
地占据面板的其余地方。
当我们增加 BottonPanels(或者任何其它我们想要的组件)到卡片面板时,add()方法的第一个自变量不是
“North”,“South”等等。相反的是,它是一个描述卡片的字符串。如果我们想轻击那张卡片使用字符
串,我们就可以使用,虽然这字符串不会显示在卡片的任何地方。使用的方法不是使用action() ;代之使用
first()、next()和 last()等方法。请查看我们有关其它方法的文件。
在Java 中,使用的一些卡片式面板结构十分的重要,因为(我们将在后面看到)在程序片编程中使用的弹出
式对话框是十分令人沮丧的。对于 Java 1。0 版的程序片而言,CardLayout 是唯一有效的取得很多不同的
“弹出式”的窗体。
13。12。5 Gr idBagLayout
很早以前,人们相信所有的恒星、行星、太阳及月亮都围绕地球公转。这是直观的观察。但后来天文学家变
得更加的精明,他们开始跟踪个别星体的移动,它们中的一些似乎有时在轨道上缓慢运行。因为天文学家知
道所有的天体都围绕地球公转,天文学家花费了大量的时间来讨论相关的方程式和理论去解释天体对象的运
行。当我们试图用GridBagLayout 来工作时,我们可以想像自己为一个早期的天文学家。基础的条例是(公
告:有趣的是设计者居然在太阳上 (这可能是在天体图中标错了位置所致,译者注))所有的天体都将遵守规
则来运行。哥白尼日新说(又一次不顾嘲讽,发现太阳系内的所有的行星围绕太阳公转。)是使用网络图来
判断布局,这种方法使得程序员的工作变得简单。直到这些增加到Java 里,我们忍耐(持续的冷嘲热讽)西
班牙的 GridBagLayout 和GridBagConstraints 狂热宗教。我们建议废止GridBagLayout 。取代它的是,使用
其它的布局管理器和特殊的在单个程序里联合几个面板使用不同的布局管理器的技术。我们的程序片看起来
不会有什么不同;至少不足以调整 GridBagLayout 限制的麻烦。对我而言,通过一个例子来讨论它实在是令
人头痛(并且我不鼓励这种库设计)。相反,我建议您从阅读 Cornell 和 Horstmann 撰写的《核心Java》
(第二版,Prentice…Hall 出版社,1997 年)开始。
在这范围内还有其它的:在JFC/Swing 库里有一个新的使用Smalltalk 的受人欢迎的“Spring and Struts”
布局管理器并且它能显著地减少GridBagLayout 的需要。
13。13 action 的替代品
正如早先指出的那样,action()并不是我们对所有事进行分类后自动为handleEvent()调用的唯一方法。有
三个其它的被调用的方法集,如果我们想捕捉某些类型的事件(键盘、鼠标和焦点事件),因此我们不得不
过载规定的方法。这些方法是定义在基础类组件里,所以他们几乎在所有我们可能安放在窗体中的组件中都
是有用的。然而,我们也注意到这种方法在Java 1。1 版中是不被支持的,同样尽管我们可能注意到继承代码
利用了这种方法,我们将会使用Java 1。1 版的方法来代替(本章后面有详细介绍)。
组件方法 何时调用
action(Event evt; Object what) 当典型的事件针对组件发生(例如,当按下一个按钮或下拉列表项目被选
中)时调用
keyDown(Event evt; int key) 当按键被按下,组件拥有焦点时调用。第二个自变量是按下的键并且是冗余
的是从evt。key 处复制来的
396
…………………………………………………………Page 398……………………………………………………………
keyup(Event evt; int key) 当按键被释放,组件拥有焦点时调用
lostFocus(Event evt; Object what) 焦点从目标处移开时调用。通常,what 是从evt。arg 里冗余复制的
gotFocus(Event evt; Object what) 焦点移动到目标时调用
mouseDown(Event evt; int x,int y) 一个鼠标按下存在于组件之上,在 X,Y 座标处时调用
mouseUp(Event evt; int x; int y) 一个鼠标升起存在于组件之上时调用
mouseMove(Event evt; int x; int y) 当鼠标在组件上移动时调用
mouseDrag(Event evt; int x; int y ) 鼠标在一次mouseDown 事件发生后拖动。所有拖动事件都会报告给
内部发生了mouseDown 事件的那个组件,直到遇到一次mouseUp 为止
mouseEnter(Event evt; int x; int y) 鼠标从前不在组件上方,但目前在
mouseExit(Event evt; int x; int y) 鼠标曾经位于组件上方,但目前不在
当我们处理特殊情况时——一个鼠标事件,例如,它恰好是我们想得到的鼠标事件存在的座标,我们将看到
每个程序接收一个事件连同一些我们所需要的信息。有趣的是,当组件的 handleEvent()调用这些方法时
(典型的事例),附加的自变量总是多余的因为它们包含在事件对象里。事实上,如果我们观察
ponent。handleEvent()的源代码,我们能发现它显然将增加的自变量抽出事件对象(这可能是考虑到在一
些语言中无效率的编码,但请记住 Java 的焦点是安全的,不必担心。)试验对我们表明这些事件事实上在被
调用并且作为一个有趣的尝试是值得创建一个过载每个方法的程序片,(action()的过载在本章的其它地
方)当事件发生时显示它们的相关数据。
这个例子同样向我们展示了怎样制造自己的按钮对象,因为它是作为目标的所有事件权益来使用。我可能会
首先(也是必须的)假设制造一个新的按钮,我们从按钮处继承。但它并不能运行。取而代之的是,我们从
画布组件处(一个非常普通组件)继承,并在其上不使用 paint()方法画出一个按钮。正如我们所看到的,
自从一些代码混入到画按钮中去,按钮根本就不运行,这实在是太糟糕了。(如果您不相信我,试图在例子
中为画布组件交换按钮,请记住调用称为super 的基础类构建器。我们会看到按钮不会被画出,事件也不会
被处理。)
myButton 类是明确说明的:它只和一个自动事件(AutoEvent)“父窗口”一起运行(父窗口不是一个基础
类,它是按钮创建和存在的窗口。)。通过这个知识,myButton 可能进入到父窗口并且处理它的文字字段,
必然就能将状态信息写入到父窗口的字段里。当然这是一种非常有限的解决方法,myButton 仅能在连结
AutoEvent 时被使用。这种代码有时称为“高度结合”。但是,制造myButton 更需要很多的不是为例子(和
可能为我们将写的一些程序片)担保的努力。再者,请注意下面的代码使用了Java 1。1 版不支持的 API。
//: AutoEvent。java
// Alternatives to action()
import java。awt。*;
import java。applet。*;
import java。util。*;
class MyButton extends Canvas {
AutoEvent parent;
Color color;
String label;
MyButton(AutoEvent parent;
Color color; String label) {
this。label = label;
this。parent = parent;
this。color = color;
}
public void paint(Graphics g) {
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!