当前位置:文档之家› 图形化界面

图形化界面

查看文章java图形界面(一)2008年10月07日星期二 22:22一. AWT 和 SWINGAWT 和 SWING 是 Java 设计 GUI 用户界面的基础。

与 AWT 的重量级组件不同,Swing 中大部分是轻量级组件。

正是这个原因,Swing 几乎无所不能,不但有各式各样先进的组件,而且更为美观易用。

所以一开始使用 AWT 的程序员很快就转向使用 Swing 了。

那为什么 AWT 组件没有消亡呢?因为 Swing 是架构在 AWT 之上的,没有AWT 就没有 Swing。

所以程序员可以根据自己的习惯选择使用 AWT 或者是Swing。

但是,最好不要二者混用——除开显示风格不同不说,还很可能造成层次 (Z-Order) 错乱,比如下例:import javax.swing.*;import java.awt.*;public class TestPanels extends JFrame {public TestPanels() {setDefaultCloseOperation(EXIT_ON_CLOSE);JPanel panel = new JPanel();for (int i = 0; i < 2; i++) {panel.add(new JButton("Button 00" + i));}JTextArea textArea = new JTextArea(5, 15);textArea.setLineWrap(true);JScrollPane scrollPane = new JScrollPane(textArea);getContentPane().add(panel, BorderLayout.NORTH);getContentPane().add(scrollPane, BorderLayout.CENTER);pack();}public static void main(String[] args) {TestPanels tp = new TestPanels();tp.show();}}运行这个程序,并用鼠标拖动那个名为“cover”的子窗口,我们会发现一个非常有趣的现象,如图:显然 cover 子窗口是在 controls 子窗口之上的,但是它只罩盖住了Swing Button,没有罩盖住 AWT Button。

再看一会儿,你是不是有这样一种感觉:Swing Button 是“画”上去的,而 AWT Button 则是“贴”上去的。

这就是二者混用造成层次错乱的一个例子。

Swing 组件有美观、易用、组件量大等特点,也有缺点——使用 Swing 组件的程序通常会比使用 AWT 组件的程序运行更慢。

但是大家都还是更喜欢用Swing 组件,原因何在?因为随着计算机硬件的升级,一点点速度已经不是问题。

相反的,用户更需要美观的用户界面,开发人员则更需要易用的开发组件。

——好,我这就来教你使用 Swing 组件开发图形用户界面的 Java 应用程序。

二. 框架、监听器和事件框架 (Frame) 是 Java 图形用户界面的基础,它就是我们通常所说的窗口,是 Windows/XWindow 应用程序的典型特征。

说到 Windows/XWindow,大家很轻易联想到“事件 (Event) 驱动”。

Java 的图形用户界面正是事件驱动的,并且由各种各样的监听器 (Listener) 负责捕捉各种事件。

假如我们需要对某一个组件的某种事件进行捕捉和处理时,就需要为其添加监听器。

比如,我们要在一个窗口 (JFrame) 激活时改变它的标题,我们就需要为这个窗口 (JFrame 对象) 添加一个可以监听到“激活窗口”这一事件的监听器——WindowListener。

怎么添加监听器呢?这通常由组件类提供的一个 addXXXXXListener 的方法来完成。

比如 JFrame 就提供有 addWindowListener 方法添加窗口监听器(WindowListener)。

一个监听器经常不只监听一个事件,而是可以监听相关的多个事件。

比如WindowListener 除了监听窗口激活事件 (windowActivate) 之外,还可以监听窗口关闭事件 (windowClosing) 等。

那么这些事件怎么区分呢?就靠重载监听器类 (Class) 的多个方法 (Method) 了,监听器监听到某个事件后,会自动调用相关的方法。

我们只要重载这个方法,就可以处理相应的事件了。

不妨先看一个例子:import javax.swing.*;import java.awt.event.*;public class TestFrame extends JFrame {private int counter = 0;public TestFrame() {/* 使用匿名类添加一个窗口监听器 */addWindowListener(new WindowAdapter() {public void windowClosing(WindowEvent e) {System.out.println("Exit when Closed event");System.exit(0); //退出应用程序}public void windowActivated(WindowEvent e) {setTitle("Test Frame " + counter++); // 改变窗口标题}});setResizable(false); // 设置窗口为固定大小setSize(200, 150);}public static void main(String[] args) {TestFrame tf = new TestFrame();tf.show();}}这个例子中,我们设计了一个窗口类(public class TestFrame extends JFrame { ...),并且为这个窗口添加了一个窗口监听器(addWindowListener(new WindowAdapter() ...)。

而我们添加的这个窗口监听器主要监听了两个事件:窗口关闭 (public void windowClosing(WindowEvent e) ...) 和窗口激活 (public void windowActivated(WindowEvent e) ...)。

在窗口关闭事件中我们退出了整个应用程序(System.exit(0);),而在窗口激活事件中,我们改变了窗口的标题 (setTitle("Test Frame " + counter++);)。

最后,我们在 main 方法中显示了这窗口类的一个实例,运行得到下图所示的结果:这个程序的运行结果就是一个什么东西都没有加的框架,也就是一个空窗口。

那么,你知道显示一个窗口最主要的几句代码吗?不知道没关系,我来告诉你,显示一个窗口只需要做三件事:生成实例(对象) -> 设置大小 -> 显示,相应的,就是下面的三句代码:JFrame frame = new JFrame("Frame's Title");frame.setSize(400, 300);frame.show();也许你会说:第一句的意思我清楚,第三句的意思我也明白,为什么一定要第二句呢?其实想想也就明白了,叫你画一个没法有大小的矩形你能画出来吗?不能。

同样,没有大小的窗口,怎么显示?所以我们需要用 setSize(int width, int height) 方法为其设置大小。

我们还有另一种方法:用 JFrame 的 pack() 方法让它自己适配一个大小。

pack() 在多数时候是令人满足的,但有时,它也会让你哭笑不得——多试试就知道了。

在JFrame 中,我们使用addWindowListener 方法加入一个监听器WindowListener (addWindowListener(new WindowAdapter() ...) 去监听发生在 JFrame 上的窗口事件。

WindowListener 是一个接口,在 java.awt.event 这个包中,但是上例中好象并没有使用WindowListener,而是使用的WindowsAdapter 吧,这是怎么回事?WindowAdapter 是 WindowsListener 接口的一个最简单的实现,也在包java.awt.event 中。

假如我们直接使用 WindowListener 产生一个匿名类,需要实现它的每一个方法 (一共 7 个)。

但 WindowAdapter 作为 WindowListener 最简单的实现,已经实现了它的每一个方法为空方法 (即只包含空语句,或者说没有语句的方法)。

用 WindowAdapter 就只需要重载可能用到的方法 (上例中只有 2 个) 就行了,而不需要再去实现每一个方法。

优点显而易见——减少代码量。

在 JFrame 上发生的窗口事件 (WindowEvent) 包括:windowActivated(WindowEvent e) 窗口得到焦点时触发windowClosed(WindowEvent e) 窗口关闭之后触发windowClosing(WindowEvent e) 窗口关闭时触发windowDeactivated(WindowEvent e) 窗口失去焦点时触发windowDeiconified(WindowEvent e)windowIconified(WindowEvent e)windowOpened(WindowEvent e) 窗口打开之后触发上例重载了其中两个方法。

假如在上例运行产生的窗口和另外一个应用程序窗口之间往返切换 (在 Windows 操作系统中你可以使用 Alt+Tab 进行切换)……试试看,你发现了什么?有没有现我们的示例窗口标题上的数字一直在增加,这便是在windowActivated 事件中setTitle("Test Frame " + counter++); 的功劳。

而另一个事件处理函数 windowClosing 中的 System.exit(0) 则保证了当窗口被关闭时退出当前的 Java 应用程序。

假如不作这样的处理会怎样呢?试验之后你会发现,窗口虽然关闭了,但程序并没有结束,但此时,除了使用 ^C 强行结束之外,恐怕也没有其它办法了。

所以,这一点非常重要:假如你想在关闭窗口的时候退出应用程序,需要你自己写代码处理 windowClosing 事件。

相关主题