2020/3/231第10章基于Swing的图形用户界面设计本章导读☆AWT组件与SWING组件☆JFrame窗体、菜单组件、布局设计☆中间容器、文本组件☆按钮与标签组件、复选框与单选按钮组件☆列表组件、表格组件、树组件和进度条组件☆窗口事件、鼠标事件、焦点事件和键盘事件☆对话框☆AWT线程与计时器☆MVC设计模式☆发布应用程序2020/3/23210.1AWT组件与SWING组件概述Java早期进行用户界面设计时,使用java.awt包中提供的类。“AWT”就是AbstracWindowToolkit(抽象窗口工具包)的缩写。Java2(JDK1.2)推出之后,增加了一个新的javax.swing包,该包提供了功能更为强大的用来设计GUI界面的类。Java早期的java.awt包中的类创建的组件习惯上称为重组件。例如,当用java.awt包中的Button类创建一个按钮组件时,都有一个相应的本地组件在为它工作(称为它的同位体)。javax.swing包为我们提供了更加丰富的、功能强大的组件,称为SWING组件,其中大部分组件是轻组件,没有同位体。SWING组件的轻组件在设计上和AWT完全不同,轻组件把与显示组件有关的许多工作和处理组件事件的工作交给相应的UI代表来完成。这些UI代表是用Java语言编写的类,这些类被增加到Java的运行环境中,因此组件的外观不依赖平台,不仅在不同平台上的外观是相同的,而且较组件有更高的性能。如果Java运行环境低于1.2版本,就不能运行含有SWING组件的程序。2020/3/233图10.1JComponent类的部分子类以及JFrame类和JDialog类2020/3/234容器类(Container)和组件类(Component)Java把由Component类的子类或间接子类创建的对象称为一个组件;把由Container的子类或间接子类创建的对象称为一个容器。◆可以向容器添加组件。Container类提供了一个public方法add(),一个容器可以调用这个方法将组件添加到该容器中。◆调用removeAll()方法可以移掉容器中的全部组件,调用remove(Componentc)方法可以移掉容器中参数指定的组件。◆每当容器添加新的组件或移掉组件时,应该让容器调用validate()方法,以保证容器中的组件能正确显示出来。容器本身也是一个组件,因此可以把一个容器添加到另一个容器中实现容器的嵌套。javax.swing包中有4个最重要的类JApplet,JFrame,JDialog和JComponent。注:JComponent类的子类都是轻组件,JComponent类是java.awt包中Container类的子类,因此所有的轻组件也都是容器。而JFrame、JApplet、JDialog都是重组件,即有同位体的组件,这样窗口(JFrame)、对话框(JDialog)、小应用程序(JavaApplet)可以和操作系统交互信息。轻组件必须在这些容器中绘制自己,习惯上称这些容器为SWING的底层容器。2020/3/23510.2JFrame窗体javax.swing包中的JFrame类是java.awt包中Frame类的子类,因此JFrame类其子类创建的对象是窗体。当应用程序需要一个窗口时,可使用JFrame或其子类创建一个对象。窗口默认地被系统添加到显示器屏幕上,因此不允许将一个窗口添加到另一个容器中。Frame类常用方法如下:◆JFrame()创建一个无标题的窗口。◆JFrame(Strings)创建一个标题为s的窗口。◆publicvoidsetBounds(inta,intb,intwidth,intheight)设置出现在屏幕上时的初始位置为(a,b),即距屏幕左面a个像素、距屏幕上方b个像素;窗口的宽是width,高是height。◆publicvoidsetSize(intwidth,intheight)设置窗口的大小,在屏幕出现默认位置是(0,0)。◆publicvoidsetVisible(booleanb)设置窗口是可见还是不可见,窗口默认是不可见的。◆publicvoidsetResizable(booleanb)设置窗口是否可调整大小,窗口默认是可调整大小的。◆publicvoidsetDefaultCloseOperation(intoperation)该方法用来设置单击窗体右上角的关闭图标后,程序会做出怎样的处理。其中的参数operation取下列有效值:1)DO_NOTHING_ON_CLOSE什么也不做2)HIDE_ON_CLOSE隐藏当前窗口3)DISPOSE_ON_CLOSE隐藏当前窗口,并释放窗体占有的其他资源4)EXIT_ON_CLOSE结束窗体所在的应用程序这4个常量都是JFrame类中的static常量,单击关闭图标后,程序根据operation取值做出不同的处理。例子10-1用JFrame创建了两个窗口,程序运行效果如图10.2。2020/3/236例子10-1运行效果图10.22020/3/23710.3菜单组件窗口中的菜单条、菜单、菜单项是我们所熟悉的界面,菜单条、菜单、菜单项是窗口常用的组件,菜单放在菜单条里,菜单项放在菜单里。1.JMenuBar菜单条JComponent类的子类JMenuBar是负责创建菜单条的,即JMenuBar的一个实例就是一个菜单条。JFrame类有一个将菜单条放置到窗口中的方法:publicvoidsetJMenuBar(JMenuBarmenubar);该方法将菜单条添加到窗口的菜单条区域(注意:只能向窗口添加一个菜单条)。2020/3/2382.JMenu菜单JComponent类的子类JMenu类是负责创建菜单的,即JMenu的一个实例就是一个菜单。JMenu类的主要方法有以下几种:◆JMenu(Strings)建立一个指定标题菜单,标题由参数s确定◆publicvoidadd(MenuItemitem)向菜单增加由参数item指定的菜单选项对象。◆publicvoidadd(Strings)向菜单增加指定的选项。◆publicJMenuItemgetItem(intn)得到指定索引处的菜单选项。◆publicintgetItemCount()得到菜单选项数目。2020/3/2393.JMenuItem菜单项JMenuItem是JMenu的父类,该类是负责创建菜单项的,即JMenuItem的一个实例就是一个菜单项。菜单项放在菜单里。JMenuItem类的主要方法有以下几种:◆JMenuItem(Strings)构造有标题的菜单项。◆JMenuItem(Stringtext,Iconicon)构造有标题和图标的菜单项◆publicvoidsetEnabled(booleanb)设置当前菜单项是否可被选择。◆publicStringgetLabel()得到菜单项的名字。◆publicvoidsetAccelerator(KeyStrokekeyStroke)为菜单项设置快捷键。为了向该方法的参数传递一个KeyStroke对象,可以使用KeyStroke类的类方法publicstaticKeyStrokegetKeyStroke(charkeyChar)返回一个KeyStroke对象;也可以使用KeyStroke类的类方法publicstaticKeyStrokegetKeyStroke(intkeyCode,intmodifiers)返回一个KeyStroke对象,其中参数keyCode取值范围为KeyEvent.VK_A~KeyEvent.VK_Z,modifiers的取值如下:InputEvent.ALT_MASK,InputEvent.CTRL_MASK和InputEvent.SHIFT_MASK。2020/3/23104.嵌入子菜单JMenu是JMenuItem的子类,因此菜单项本身还可以是一个菜单,这样的菜单项称为子菜单。为了使得菜单项有一个图标,可以用图标类Icon声明一个图标,然后使用其子类ImageIcon类创建一个图标,如Iconicon=newImageIcon(dog.gif);下面的例10-2中有一个含有菜单的窗口(效果如图10.3所示)。2020/3/231110.4布局设计当把组件添加到容器中时,希望控制组件在容器中的位置,这就需要学习布局设计的知识。本节将介绍java.awt包中的FlowLayout、BorderLayout、CardLayout、GridLayout布局类和java.swing.border包中的BoxLayout布局类。容器可以使用方法setLayout(布局对象);来设置自己的布局。对于JFrame窗口,默认布局是BorderLayout布局。2020/3/23121.FlowLayout布局FlowLayout类的对象称为FlowLayout布局。FlowLayout类的一个常用构造方法如下:◆FlowLayout();构造方法可以创建一个居中对齐的布局对象,如:FlowLayoutflow=newFlowLayout();◆con.setLayout(flow);容器con使用flow这个布局对象◆容器con可以使用Container类提供的add()方法将组件顺序地添加到容器中。◆FlowLayout布局对象调用setAlignment(intaligin)方法可以重新设置布局的对齐方式,其中aligin可以取值FlowLayout.LEFT、FlowLayout.CENTER或FlowLayout.RIGHT。◆FlowLayout布局对象调用setHgap(inthgap)方法和setVgap(intvgap)方法可以重新设置布局的水平间隙和垂直间隙。◆如果需要改变最佳大小,组件需调用:publicvoidsetPreferredSize(DimensionpreferredSize)设置大小,例如:button.setPreferredSize(newDimension(20,20));注:对于添加到使用FlowLayout布局的容器中的组件,组件调用setSize(intx,inty)设置的大小无效。例10-3中,JFrame使用FlowLayout布局放置10个组件(效果如图10.4所示)。2020/3/2313例子10-3运行效果图10.42020/3/23142.BorderLayout布局BorderLayout布局是Window容器的默认布局。JFrame、JDialog都是Window类的间接子类,它们的内容面板的默认布局都是BorderLayout布局。如果一个容器使用这种布局,那么容器空间简单地划分为东、西、南、北、中五个区域。每加入一个组件都应该指明把这个组件添加在哪个区域中,区域由BorderLayout中的静态常量CENTER、NORTH、SOUTH、WEST、EAST表示。例如,一个使用BorderLayout布局的容器con,可以使用add()方法将一个组件b添加到中心区域:con.add(b,BorderLayout.CENTER);或con.add(BorderLayour.CENTER,b);注:添加到某个区域的组件将占据整个这个区域.每个区域只能放置一个组件,如果向某个已放置了组件的区域再放置一个组件,那么先前的组件将被后者替换。注:使用BorderLayout布局的容器最多能添加5个组件,如果容器中需要添加的组件超过5个,就必须使用容器的嵌套或改用其他布局策略。例10-4使用了BorderLayout布局(效果如图10.5所示)。2020/3/2315例子10-4运行效果图10.52020/3/23163.CardLayout布局使用CardLayout容器可以容纳多个组件,但同一时刻容器只能从这些组件中选出一个来显示,就像一叠“扑克牌”每次只能显示最上面的一张一样,这个被显示的组件将占据