友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
富士康小说网 返回本书目录 加入书签 我的书架 我的书签 TXT全本下载 『收藏到我的浏览器』

Java编程思想第4版[中文版](PDF格式)-第72部分

快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!



样组成菜单,每个菜单怎样组成菜单项(MenuItems),chenkboxMenuItems 或者其它的菜单(产生子菜 

单)。当菜单组合后,可以用setMenuBar()方法安装到现在的程序中。值得注意的是当按钮被压下时,它将 

检查当前的菜单安装使用getMenuBar(),然后安放其它的菜单条在它的位置上。  

当测试是“open”(即开始)时,注意拼写和大写,如果开始时没有对象,Java 发出no error (没有错误) 

的信号。这种字符串比较是一个明显的程序设计错误源。  

校验和非校验的菜单项自动地运行,与之相关的CheckBoxMenuItems 着实令人吃惊,这是因为一些原因它们 

不允许字符串匹配。(这似乎是自相矛盾的,尽管字符串匹配并不是一种很好的办法。)因此,我们可以匹 



                                                                                          403 


…………………………………………………………Page 405……………………………………………………………

配一个目标对象而不是它们的标签。当演示时,getState()方法用来显示状态。我们同样可以用setState() 

改变CheckboxMenuItem 的状态。  

我们可能会认为一个菜单可以合理地置入超过一个的菜单条中。这看似合理,因为所有我们忽略的菜单条的 

add()方法都是一个句柄。然而,如果我们试图这样做,这个结果将会变得非常的别扭,而远非我们所希望得 

到的结果。(很难知道这是一个编程中的错误或者说是他们试图使它以这种方法去运行所产生的。)这个例 

子同样向我们展示了为什么我们需要建立一个应用程序以替代程序片。(这是因为应用程序能支持菜单,而 

程序片是不能直接使用菜单的。)我们从帧处继承代替从程序片处继承。另外,我们为类建一个构建器以取 

代 init()安装事件。最后,我们创建一个main()方法并且在我们建的新型对象里,调整它的大小,然后调用 

show()。它与程序片只在很小的地方有不同之处,然而这时它已经是一个独立的设置窗口应用程序并且我们 

可以使用菜单。  



13。15。2 对话框  



对话框是一个从其它窗口弹出的窗口。它的目的是处理一些特殊的争议和它们的细节而不使原来的窗口陷入 

混乱之中。对话框大量在设置窗口的编程环境中使用,但就像前面提到的一样,鲜于在程序片中使用。  

我们需要从对话类处继承以创建其它类型的窗口、像帧一样的对话框。和窗框不同,对话框不能拥有菜单条 

也不能改变光标,但除此之外它们十分的相似。一个对话框拥有布局管理器(默认的是BorderLayout 布局管 

理器)和过载action()等等,或用 handleEvent() 去处理事件。我们会注意到handleEvent() 的一个重要差 

异:当WINDOW_DESTORY 事件发生时,我们并不希望关闭正在运行的应用程序!  

相反,我们可以使用对话窗口通过调用 dispace()释放资源。在下面的例子中,对话框是由定义在那儿作为 

类的ToeButton 的特殊按钮组成的网格构成的(利用GridLayout 布局管理器)。ToeButton 按钮围绕它自已 

画了一个帧,并且依赖它的状态:在空的中的“X”或者“O”。它从空白开始,然后依靠使用者的选择, 

转换成“X”或“O”。但是,当我们单击在按钮上时,它会在“X”和“O”之间来回交换。(这产生了 

一种类似填字游戏的感觉,当然比它更令人讨厌。)另外,这个对话框可以被设置为在主应用程序窗口中为 

很多的行和列变更号码。  

  

//: ToeTest。java  

// Demonstration of dialog boxes  

// and creating your own ponents  

import java。awt。*;  

  

class ToeButton extends Canvas {  

  int state = ToeDialog。BLANK;  

  ToeDialog parent;  

  ToeButton(ToeDialog parent) {  

    this。parent = parent;  

  }  

  public void paint(Graphics  g) {  

    int x1 = 0;  

    int y1 = 0;  

    int x2 = size()。width 1;  

    int y2 = size()。height 1;  

    g。drawRect(x1; y1; x2; y2);  

    x1 = x2/4;  

    y1 = y2/4;  

    int wide = x2/2;  

    int high = y2/2;  

    if(state == ToeDialog。XX) {  

      g。drawLine(x1; y1; x1 + wide; y1 + high);  

      g。drawLine(x1; y1 + high; x1 + wide; y1);  

    }  

    if(state == ToeDialog。OO) {  

      g。drawOval(x1; y1; x1+wide/2; y1+high/2);  



                                                                                    404 


…………………………………………………………Page 406……………………………………………………………

    }  

  }  

  public boolean   

  mouseDown(Event evt; int x; int y) {  

    if(state == ToeDialog。BLANK) {  

      state = parent。turn;  

      parent。turn= (parent。turn == ToeDialog。XX ?  

        ToeDialog。OO : ToeDialog。XX);  

    }   

    else  

      state = (state == ToeDialog。XX ?   

        ToeDialog。OO : ToeDialog。XX);  

    repaint();  

    return true;  

  }  

}  

  

class ToeDialog extends Dialog {  

  // w = number of cells wide  

  // h = number of cells high  

  static final int BLANK = 0;  

  static final int XX = 1;  

  static final int OO = 2;  

  int turn = XX; // Start with x's turn  

  public ToeDialog(Frame parent; int w; int h) {  

    super(parent; 〃The game itself〃; false);  

    setLayout(new GridLayout(w; h));  

    for(int i = 0; i 《 w * h; i++)  

      add(new ToeButton(this));  

    resize(w * 50; h * 50);  

  }  

  public boolean handleEvent(Event evt) {  

    if(evt。id == Event。WINDOW_DESTROY)   

      dispose();  

    else   

      return super。handleEvent(evt);  

    return true;  

  }  

}  

  

public class ToeTest extends Frame {  

  TextField rows = new TextField(〃3〃);  

  TextField cols = new TextField(〃3〃);  

  public ToeTest() {  

    setTitle(〃Toe Test〃);  

    Panel p = new Panel();  

    p。setLayout(new GridLayout(2;2));  

    p。add(new Label(〃Rows〃; Label。CENTER));  

    p。add(rows);  

    p。add(new Label(〃Columns〃; Label。CENTER));  

    p。add(cols);  

    add(〃North〃; p);  



                                                                                             405 


…………………………………………………………Page 407……………………………………………………………

    add(〃South〃; new Button(〃go〃));  

  }  

  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(arg。equals(〃go〃)) {  

      Dialog d = new ToeDialog(  

        this;   

        Integer。parseInt(rows。getText());  

        Integer。parseInt(cols。getText()));  

      d。show();  

    }   

    else   

      return super。action(evt; arg);  

    return true;  

  }  

  public stat ic void main(String'' args) {  

    Frame f = new ToeTest();  

    f。resize(200;100);  

    f。show();  

  }  

} ///:~  

  

ToeButton 类保留了一个句柄到它 ToeDialog 型的父类中。正如前面所述,ToeButton 和 ToeDialog 高度的结 

合因为一个 ToeButton 只能被一个ToeDialog 所使用,但它却解决了一系列的问题,事实上这实在不是一个 

糟糕的解决方案因为没有另外的可以记录用户选择的对话类。当然我们可以使用其它的制造ToeDialog。turn 

 (ToeButton 的静态的一部分)方法。这种方法消除了它们的紧密联系,但却阻止了我们一次拥有多个 

ToeDialog (无论如何,至少有一个正常地运行)。  

paint()是一种与图形有关的方法:它围绕按钮画出矩形并画出“X”或“O”。这完全是冗长的计算,但却 

十分的直观。  

一个鼠标单击被过载的 mouseDown()方法所俘获,最要紧的是检查是否有事件写在按钮上。如果没有,父窗 

口会被询问以找出谁选择了它并用来确定按钮的状态。值得注意的是按钮随后交回到父类中并且改变它的选 

择。如果按钮已经显示这为“X”和“O”,那么它们会被改变状态。我们能注意到本书第三章中描述的在 

这些计算中方便的使用的三个一组的 If…else。当一个按钮的状态改变后,按钮会被重画。  

ToeDialog 的构建器十分的简单:它像我们所需要的一样增加一些按钮到 GridLayout 布局管理器中,然后调 

整每个按钮每边大小为 50 个像素(如果我们不调整窗口,那么它就不会显示出来)。注意 handleEvent()正 

好为WINDOW_DESTROY 调用dispose(),因此整个应用程序不会被关闭。  

ToeTest 设置整个应用程序以创建 TextField (为输入按钮网格的行和列)和“go”按钮。我们会领会 

action()在这个程序中使用不太令人满意的“字符串匹配”技术来测试按钮的按下(请确定我们拼写和大写 

都是正确的!)。当按钮按下时,TextField 中的数据将被取出,并且,因为它们在字符串结构中,所以需 

要利用静态的 Integer。paresInt()方法来转变成中断。一旦对话类被建立,我们就必须调用 show()方法来显 

示和激活它。  

我们会注意到ToeDialog 对象赋值给一个对话句柄 d。这是一个上溯造型的例子,尽管它没有真正地产生重 

要的差异,因为所有的事件都是show()调用的。但是,如果我们想调用ToeDialog 中已经存在的一些方法, 

我们需要对 ToeDialog 句柄赋值,就不会在一个上溯中丢失信息。  

  

1。 文件对话类  



                                                                                       406 


…………………………………………………………Page 408……………………………………………………………

在一些操作系统中拥有许多的特殊内建对话框去处理选择的事件,例如:字库,颜色,打印机以及类似的事 

件。几乎所有的操作系统都支持打开和保存文件,但是,Java 的FileDialog 包更容易使用。当然这会不再 

检测所有使用的程序片,因为程序片在本地磁盘上既不能读也不能写文件。(这会在新的浏览器中交换程序 

片的信任关系。)  

下面的应用程序运用了两个文件对话类的窗体,一个是打开,一个是保存。大多数的代码到如今已为我们所 

熟悉,而所有这些有趣的活动发生在两个不同按钮单击事件的 action()方法中。  

  

//: FileDialogTest。java  

// Demonstration of File dialog boxes  

import java。awt。*;  

  

public class FileDialogTest extends Frame {  

  TextField filename = new TextField();  

  TextField directory = new TextField();  

  Button open = new Button(〃Open〃);  

  Button save = new Button(〃Save〃);  

  public FileDialogTest() {  

    setTitle(〃File Dialog Test〃);  

    Panel p = new Panel();  

    p。setLayout(new FlowLayout());  

    p。add(open);  

    p。add(save);  

    add(〃South〃; p);  

    directory。setEditable(false);  

    filename。setEditable(false);  

    p = new Panel();  

    p。setLayout(new GridLayout(2;1));  

    p。add(filename);  

    p。add(directory);  

    add(〃North〃; p);  

  }  

  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(open)) {  

      // Two arguments; defaults to open file:  

      FileDialog d = new FileDialog(this;  

        〃What file do you want to open?〃);  

      d。setFile(〃*。java〃); // Filename filter  

      d。setDirectory(〃。〃); // Current directory  

      d。show();  

      String openFile;  

      if((openFile = d。getFile()) != null) {  

        filename。setText(openFile);  

        directory。setText(d。getDirectory());  

      } else {  

        filename。setText(〃You pressed cancel〃);  



                                                                                          407 


…………………………………………………………Page 409……………………………………………………………

        directory。setText(〃〃);  

      }  

    }   

    else if(evt。target。equals(save)) {  

      FileDialog d = new FileDialog(this;  

        〃What file do you want to save?〃;  

        FileDialog。SAVE);  

      d。setFile(〃*。java〃);  

      d。setDirectory(〃。〃);  

      d。show();  

      String saveFile;  

      if((saveFile = d。getFile()) != null) {  

        filename。setText(saveFile);  

        directory。setText(d。getDirectory());  

      } else {  

        filename。setText(〃You pressed cancel〃);  

        directory。setText(〃〃);  

      }  

    }   

    else   

      return super。action(evt; arg);  

    return true;  

  }  

  public static void main(String'' args) {  

    Frame f = new FileDialogTest();  

    f。resize(250;110);  

    f。show();  

  }  

} ///:~  

  

对一个“打开文件”对话框,我们使用构建器设置两个自变量;首先是父窗口句柄,其次是 FileDialog 标题 

条的标题。setFile()方法提供一个初始文件名--也许本地操作系统支持通配符,因此在这个例子中所有 

的。java 文件最开头会被显示出来。setDirectory()方法选择文件决定开始的目录(一般而言,操作系统允 

许用户改变目录)。  

show()命令直到对话类关闭才返回。FileDialog 对象一直存在,因此我们可以从它那里读取数据。如果我们 

调用getFile()并且它返回空,这意味着用户退出了对话类。文件名和调用getDirectory()方法的结果都显 

示在TextFields 里。  

按钮的保存工作使用同样的方法,除了因为FileDialog 而使用不同的构建器。这个构建器设置了三个自变量 

并且第三的一个自变量必须为FileDialog。SAVE 或 FileDialog。OPEN。  



13。16 新型 AWT   



在Java 1。1 中一个显著的改变就是完善了新AWT 的创新。大多数的改变围绕在 Java 1。1 中使用的新事件模 

型:老的事件模型是糟糕的、笨拙的、非面向对象的,而新的事件模型可能是我所见过的最优秀的。难以理 

解一个如此糟糕的(老的 AWT )和一个如此优秀的(新的事件模型)程序语言居然出自同一个集团之手。新 

的考虑事件的方法看来中止了,因此争议不再变成障碍,从而轻易进入我们的意识里;相反,它是一个帮助 

我们设计系统的工具。它同样是Java Beans 的精华,我们会在本章后面部分进入讲述。  

新的方法设计对象做为“事件源”和“事件接收器”以代替老 AWT 的非面向对象串联的条件语句。正象我们 

将看到的内部类的用途是集成面向对象的原始状态的新事件。另外,事件现在被描绘为在一个类体系以取代 

单一的类并且我们可以创建自己的事件类型。  

我们同样会发现,如果我们采用老的AWT 编程,Java 1。1 版会产生一些看起来不合理的名字转换。例如, 

setsize()改成resize() 。当我们学习Java Beans 时这会变得更加的合理,因为 Beans 使用一个独特的命名 

协议。名字必须被修改以在Beans 中产生新的标准AWT 组件。  



                                                                                        408 


…………………………………………………………Page 410……………………………………………………………

剪贴板操作在Java 1。1 版中也得到支持,尽管拖放操作“将在新版本中被支持”。我们可能访问桌面色彩组 

织,所以我们的Java 可以同其余桌面保持一致。可以利用弹出式菜单,并且为图像和图形作了改进。也同样 

支持鼠标操作。还有简单的为打印的API 以及简单地支持滚动。  



13。16。1 新的事件模型  



在新的事件模型的组件可以开始一个事件。每种类型的事件被一个个别的类所描绘。当事件开始后,它受理 

一个或更多事件指明“接收器”。因此,事件源和处理事件的地址可以被分离。  

每个事件接收器都是执行特定的接收器类型接口的类对象。因此作为一个程序开发者,我们所要做的是创建 

接收器对象并且在被激活事件的组件中进行注册。event…firing 组件调用一个 addXXXListener()方法来完成 

注册,以描述XXX 事件类型接受。我们可以容易地了解到以 addListened 名的方法通知我们任何的事件类型 

都可以被处理,如果我们试图接收事件我们会发现编译时我们的错误。Java Beans 同样使用这种 

addListener 名的方法去判断那一个程序可以运行。  

我们所有的事件逻辑将装入到一个接收器类中。当我们创建一个接收器类时唯一的一点限制是必须执行专用 

的接口。我们可以创建一个全局接收器类,这种情况在内部类中有助于被很好地使用,不仅仅是因为它们提 

供了一个理论上的接收器类组到它们服务的UI 或业务逻辑类中,但因为(正像我们将会在本章后面看到的) 

事实是一个内部类维持一个句柄到它的父对象,提供了一个很好的通过类和子系统边界的调用方法。  

一个简单的例子将使这一切变得清晰明确。同时思考本章前部 Button2。java 例子与这个例子的差异。  

  

//: Button2New。java  

// Capturing button presses  

import java。awt。*;  

import java。awt。event。*; // Must add this  

import java。applet。*;  

  

public class Button2New extends Applet {  

  Button  

    b1 = new Button(〃Button 1〃);  

    b2 = new Button(〃Button 2〃);  

  public void init() {  

    b1。addActionListener(new B1());  

    b2。addActionListener(new B2());  

    add(b1);  

    add(b2);  

  }  

  class B1 implements ActionListener {  

    public void actionPerformed(ActionEvent e) {  

      getAppletContext()。showStatus(〃Button 1〃);  

    }  

  }  

  class B2 implements ActionListener {  

    public voi
返回目录 上一页 下一页 回到顶部 10 9
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!