- 写在前面的话
- 引言
- 第 1 章 对象入门
- 第 2 章 一切都是对象
- 第 3 章 控制程序流程
- 第 4 章 初始化和清除
- 第 5 章 隐藏实施过程
- 第 6 章 类再生
- 第 7 章 多形性
- 第 8 章 对象的容纳
- 第 9 章 违例差错控制
- 第 10 章 Java IO 系统
- 第 11 章 运行期类型鉴定
- 第 12 章 传递和返回对象
- 第 十三 章 创建窗口和程序片
- 第 14 章 多线程
- 第 15 章 网络编程
- 第 16 章 设计范式
- 第 17 章 项目
- 附录 A 使用非 JAVA 代码
- 附录 B 对比 C++和 Java
- 附录 C Java 编程规则
- 附录 D 性能
- 附录 E 关于垃圾收集的一些话
- 附录 F 推荐读物
13.15.1 菜单
直接在程序片中安放一个菜单是不可能的(Java 1.0,Java1.1 和 Swing 库不允许),因为它们是针对应用程序的。继续,如果您不相信我并且确定在程序片中可以合理地拥有菜单,那么您可以去试验一下。程序片中没有 setMenuBar() 方法,而这种方法是附在菜单中的(我们会看到它可以合理地在程序片产生一个帧,并且帧包含菜单)。
有四种不同类型的 MenuComponent(菜单组件),所有的菜单组件起源于抽象类:菜单条(我们可以在一个事件帧里拥有一个菜单条),菜单去支配一个单独的下拉菜单或者子菜单、菜单项来说明菜单里一个单个的元素,以及起源于 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"); 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)) { 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 或者其它的菜单(产生子菜单)。当菜单组合后,可以用 setMenuBar() 方法安装到现在的程序中。值得注意的是当按钮被压下时,它将检查当前的菜单安装使用 getMenuBar(),然后安放其它的菜单条在它的位置上。
当测试是“open”(即开始)时,注意拼写和大写,如果开始时没有对象,Java 发出 no error(没有错误)的信号。这种字符串比较是一个明显的程序设计错误源。
校验和非校验的菜单项自动地运行,与之相关的 CheckBoxMenuItems 着实令人吃惊,这是因为一些原因它们不允许字符串匹配。(这似乎是自相矛盾的,尽管字符串匹配并不是一种很好的办法。)因此,我们可以匹配一个目标对象而不是它们的标签。当演示时,getState() 方法用来显示状态。我们同样可以用 setState() 改变 CheckboxMenuItem 的状态。
我们可能会认为一个菜单可以合理地置入超过一个的菜单条中。这看似合理,因为所有我们忽略的菜单条的 add() 方法都是一个句柄。然而,如果我们试图这样做,这个结果将会变得非常的别扭,而远非我们所希望得到的结果。(很难知道这是一个编程中的错误或者说是他们试图使它以这种方法去运行所产生的。)这个例子同样向我们展示了为什么我们需要建立一个应用程序以替代程序片。(这是因为应用程序能支持菜单,而程序片是不能直接使用菜单的。)我们从帧处继承代替从程序片处继承。另外,我们为类建一个构建器以取代 init() 安装事件。最后,我们创建一个 main() 方法并且在我们建的新型对象里,调整它的大小,然后调用 show()。它与程序片只在很小的地方有不同之处,然而这时它已经是一个独立的设置窗口应用程序并且我们可以使用菜单。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论