前言
到目前为止,我们编写的程序都是通过键盘接收输入,在控制台屏幕上显示结果。绝大多数用户并不喜欢这种交互方式。现代的程序早已不采用这种操作方法,网络程序更是如此。
从本章开始,我们将介绍如何编写使用图形用户界面(GUI)的Java程序。其中,主要讲述如何编写定义屏幕上的窗口大小和位置的程序;如何在窗口中采用多种字体显示文本;如何显示图像等等。这些都是需要掌握的编程技能,在后续章节中,将会使用这些技术编写一些很有趣味的程序。
Swing概述
在Java 1.0刚刚出现的时候,包含了一个用于基本GUI程序设计的类库,Sun将它称为抽象窗
口工具箱(Abstract Window Toolkit,AWT)。基本AWT库采用将处理用户界面元素的任务委派给每个目标平台(Windows、Solaris、Macintosh等等)的本地GUI工具箱的方式,由本地GUI工具箱负责用户界面元素的创建和动作。例如,如果使用最初的AWT在Java窗口中放置一个文本框,就会有一个低层的“对等体”文本框,用它来实际地处理文本输入。从理论上说,结果程序可以运行在任何平台上,但观感(look and feel)的效果却依赖于目标平台,因此,Sun公司的口号是“一次编写,随处使用”。
对于简单的应用程序来说,基于对等体方法的效果还是不错的,但是,要想编写依赖于本地用户界面元素的高质量、可移植的图形库就会显现出缺陷了。例如,菜单、滚动条和文本域这些用户界面元素,在不同的平台上,操作行为存在着一些微妙的差别。因此,要想给予用户一致的、可预见性的界面操作方式是相当困难的。而且,有些图形环境(如X11/Motif)并没有像Windows或Macintosh这样丰富的用户界面组件集合。这也就将基于对等体的可移植库限制在了“最小公分母”的范围内。其结果使AWT构建的GUI应用程序看起来没有Windows或Macintosh应用程序显示的那么漂亮,也没有提供那些平台用户所认知的功能。更加糟糕的是,在不同平台上的AWT用户界面库中存在着不同的bug。研发人员必须在每一个平台上测试他们的应用程序,因此人们嘲弄地将AWT称为“一次编写,到处调试”。
在1996年,Netscape创建了一种称为IFC(Internet Foundation Class)的GUI库,它采用了与AWT完全不同的工作方式。它将按钮、菜单这样的用户界面元素绘制在空白窗口上,而对等体只需要创建和绘制窗口。因此,Netscape的IFC部件在程序运行的所有平台上的外观和动作都一样。Sun与Netscape合作完善了这种方式,创建了一个名为Swing(有时称为Swing集)的用户界面库。Swing可作为Java 1.1的扩展部分使用,现已成为JDK 1.2标准库的一部分,
就像Duke Ellington所说的那样:“如果没有Swing,Java图形界面就没有任何意义”。现在,Swing是不对等基于GUI工具箱的正式名字。它已是Java基础类库(Java Foundation Class,JFC)的一部分。完整的JFC十分庞大,其中包含的内容远远大于Swing GUI工具箱。JFC特性不仅仅包含了Swing组件,而且还包含了一个可访问的API、一个2D API和一个可拖拽的API。
注意:Swing没有完全替代AWT,而是基于AWT架构之上。Swing仅仅提供了能力更加强大的用户界面组件。尤其在采用Swing编写的程序中,还需要使用基本的AWT处理事件。从现在开始,“Swing”是指“被绘制的”非对等体用户界面类;“AWT”是指像事件处理这样的窗口工具箱的低层机制。
当然,在用户屏幕上显示基于Swing用户界面的元素要比显示AWT的基于对等体组件的速度慢一些。鉴于以往的经验,对于任何一台现代的计算机来说,微小的速度差别无妨大碍。另外,由于下列几点无法抗拒的原因,驱使人们选择Swing:
• Swing拥有一个丰富、便捷的用户界面元素集合。
• Swing对低层平台依赖的很少,因此与平台相关的bug很少。
• Swing给予不同平台的用户一致的感观效果。
所有这些意味着Swing拥有履行Sun提出的“一次编写,到处运行”承诺的能力。
不过,上面第三点存在着一个潜在的问题:如果在所有平台上用户界面元素看起来都一样,那么,它们就有可能与本地控件不一样,而这些平台的用户对此可能并不熟悉。
Swing采用了一种很巧妙的方式来解决这个问题。在程序员编写Swing程序时,可以为程序指定专门的“观感”。
例如,图7-1和图7-2展示了同一个程序在Windows 和Motif平台下运行的观感。
![bf9f931e6206fab48c237c0654922033.png](https://i-blog.csdnimg.cn/blog_migrate/ee52ac1ef20d12545ff928d0961a32c8.jpeg)
![2f41b4a9ad69662480ee0def679dbfbe.png](https://i-blog.csdnimg.cn/blog_migrate/6d16d3492eb1e5c638c25358307c3982.jpeg)
注意:尽管本书并没有打算介绍有关设定“观感”的方式,但Java程序员可以对已存在的观感进行扩展,甚至还可以设计全新的观感。设计Swing组件的绘制方式是一个很繁琐的过程。有些程序员已经做过一些这样的工作,尤其是将Java移植到信息亭(kiosk)终端和手持设备这样的非传统平台上。请参阅 http://www.javooto.com,其中包含了一系列有趣的观感实现。
JDK 5.0引入了一种被称为Synth的新观感方式,使用它处理比较容易。在Synth中,可以通过指定图像文件和XML描述符定义一种新观感,而不需要编写任何代码。
此外,Sun开发了一种被称为“Metal”的独立于平台的观感。现在,市场上人们将它称为“Java观感”。不过,绝大多数程序员还继续沿用着“Metal”这个术语,在本书中也将这样称呼。
有些人批评Metal有点笨重,而在版本5.0中看起来却焕然一新(请看图7-3)。
![0493f8c3a44bc434dd98810226feadf7.png](https://i-blog.csdnimg.cn/blog_migrate/63c524243c1b39e16b63189cc8efde33.jpeg)
现在,Metal外观支持多种主题,每一种主题的颜色和字体都有微小的变化。
默认的主题叫做“Ocean”。在本文中,所有的图形程序都将采用Swing的Metal观感和Ocean主题。
注意:绝大多数Java用户界面程序设计都采用Swing,但有一个特别的例外。Eclipse集成开发环境使用了一种与AWT类似,且被称为SWT的图形工具箱,它可以映射到不同平台的本地组件上。
有关SWT的描述可以在网站http://www.eclipse.org/ articles/找到。
最后,给大家一个忠告,如果使用过Visual Baisc或C# 编写Microsoft Windows应用程序,就应该了解这些产品提供的图形布局工具和资源编辑器带来的便利。这些工具可以用来设计应用程序的外观,然后生成大部分(有时是全部)GUI代码。尽管也有一些Java程序设计的GUI构造器,但它们与相应的Windows工具相比较起来还很不成熟。不管怎样,要想完全地掌握图形用户界面程序(乃至有效地使用这些工具),就需要知道如何手工地创建用户界面。当然,通常需要编写大量的代码。
创建框架
在Java中,顶层窗口(就是没有包含在其他窗口中的窗口)被称为框架(frame)。在AWT库中有一个称为Frame的类,用于描述顶层窗口。这个类的Swing版本名为JFrame,它扩展于Frame类。JFrame是极少数几个不绘制在画布上的Swing组件之一。因此,它的修饰部件(按钮、标题栏、图标等)由用户的窗口系统绘制,而不是由Swing绘制。
警告:大多数的Swing组件类都以“J”开头,例如,JButton、JFrame等等。在Java中有Button和Frame这样的类,但它们属于AWT组件。如果偶然地忘记了书写“J”,程序仍然可以进行编译和运行,但是将Swing和AWT组件混合在一起使用将会导致视觉和行为的不一致。
在本节中,将介绍有关Swing的JFrame的常用方法。例7-1给出了一个在屏幕中显示一个空框架的简单程序。如图7-4所示。
![9f3fc9e7cb8d0864688c96426dba8d3a.png](https://i-blog.csdnimg.cn/blog_migrate/11c343935ad008feaa7ba2f60793e1b9.jpeg)
例7-1 SimpleFrameTest.java
![56539c3a8cf8fd58ee0708c2008eb8bf.png](https://i-blog.csdnimg.cn/blog_migrate/3391ccc877798a84733d6f2d5cb77b34.jpeg)
![b91d2b1a62914b37a1b3a574df9f9d91.png](https://i-blog.csdnimg.cn/blog_migrate/0a277afe17f2fea7f1d33e488dc2f6e0.jpeg)
下面逐行地讨论一下这个程序。
Swing类位于javax.swing包中。包名javax表示这是一个Java扩展包,而不是核心包。Swing类实际上是对Java 1.1的扩展。由于Swing类不是核心层次的一部分,所以尽可能地将Swing类加载到Java 1.1兼容的浏览器中(浏览器的安全管理器不允许添加任何以“java.”开头的包)。在Java 2平台上,Swing包不再是扩展部分,而是核心层的一部分。任何与Java 2兼容的Java实现都必须提供Swing类。不过,为了与Java 1.1代码兼容,保留了javax名字。(实际上,Swing包最早是com.sun.java.swing,后来在Java 2的beta版本中简化为java.awt.swing,最后在Java 2后期的beta版本中又改回为com.java.swing,在Java程序员的抗议呼声下,最终改为javax.swing。)
在默认情况下,框架的大小为0×0像素,这种框架没有什么实际意义。我们定义了一个子类SimpleFrame,它的构造器将框架大小设置为300×200像素。在SimpleFrameTest类的main方法中,程序将由创建一个SmpleFrame对象开始运行。
接下来,我们定义了用户关闭这个框架时的响应动作。对于这个程序而言,我们只是让程序退出。选择这个响应动作的语句是:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
在包含多个框架的程序中,不能因为用户关闭了其中的一个框架就让程序退出。在默认情况下,用户关闭窗口时只是将框架隐藏了起来,而程序并没有终止。
简单地构造一个框架并不自动显示出来,框架起初是不可见的。这就给程序员了一个机会,可以在框架第一次显示之前往其中添加组件。为了显示框架,main方法需要调用框架的setVisible方法。
然后,main方法退出。需要注意,退出main并没有终止程序,终止的只是主线程。目前显示的框架激活了用户界面线程,以保持程序处于激活状态。
注意:在JDK 5.0以前的版本中,可以使用JFrame类从超类Window继承show方法。Window类的超类是Component,其中也有一个show方法。在JDK 1.2中不提倡使用Component.show。如果想要显示一个组件,建议调用setVisible(true)。然而,JDK 1.4以前的版本,并没有反对使用Window.show方法。事实上,这个方法很实用,它可以让窗口可见,且置于其他窗口的前面。遗憾的是,由于不提倡使用它,随之也失去了这一好处,JDK 5.0也不赞成使用show显示窗口。
图7-4中显示的是运行例7-1程序的结果,它只是一个很乏味的顶层窗口。在这个图中看到的标题栏和外框装饰(比如,重置窗口大小的拐角)都是由操作系统绘制的,而不是Swing库。如果在X Windows下运行同样的程序,对框架的装饰是不一样的。Swing库负责绘制框架内的所有内容。在这个程序中,只用默认的背景色填充了框架。
注意:在JDK 1.4中,可以调用frame.setUndecorated(true) 关闭所有框架装饰。
注意:在前面的例子中编写了两个类,一个用于定义框架类,另一个包含了创建和显示框架对象的main方法。在很多程序中,经常会发现main方法被包装成一个很简捷的类,如下所示:
![5a96eea637667036f085c6ae88f70c0e.png](https://i-blog.csdnimg.cn/blog_migrate/391ce179a2893e9ca0595b75b70ed8dd.jpeg)
![6f0ffbb3e637317eb325888edfdd7345.png](https://i-blog.csdnimg.cn/blog_migrate/674f7698dad72c198ae079eb72ccf278.jpeg)
从某种意义上说,调用框架类中的main方法的代码启动程序是比较简单的。这样不必引入其他的辅助类。然而,有相当多的程序员感觉这种程序风格有点混乱。
因此,更愿意将启动程序的类与定义用户界面的类分开。
觉得文章不错的话,可以转发关注小编一波,每天持续更新好文!!!
明天讲框架定位和在面板中显示信息~~