资源描述
第7章 图形用户界面图形用户界面(Graphics User Interface, GUI),是指用图形的方式实现用户与计算机之间的交互。它通过图形的方式,借助菜单、按钮等标准界面元素和鼠标操作,帮助用户方便地向计算机发出命令,启动程序,并将程序的运行结果同样以图形的形式显示给用户。GUI通常由GUI组件(有时称为控件或窗口小部件)构成。GUI组件是用户通过鼠标、键盘或其它诸如声音识别等输入形式与应用程序进行交互的对象。学习Java的GUI设计就必须了解几个概念:容器、组件、容器布局、事件处理机制。本章将通过实例剖析Swing常用组件的功能、如何在组件中绘图、各种事件的应用、以及各种布局的设置等问题。7.1 Java GUI概述随着JDK1.2(现改名为Java 2)的发布,Java的API有两套完整的按钮、菜单、文本域以及其它GUI组件:抽象窗口工具集(Abstract Window Toolkit ,AWT)和Swing组件集。AWT从JDK1.0开始就是Java的一部分,由AWT扩展而来的Swing组件集,是Java1.2引入的新的GUI组件库。二者均包括在JFC(Java Foundation Classes,Java基础类)中,JFC是一组支持在流行平台的客户端应用程序中创建GUI和图形功能的Java类库,作为J2SE的一个有机部分,主要包含五个部分,即AWT、Java2D、Accessibility、Drag&Drop、Swing,它是一套帮助开发人员设计复杂应用程序的开发包。7.1.1 AWT与SwingAWT是Java2版本之前的Java平台提供的一套图形用户界面组件类型。AWT库最重要的特征之一是,它与运行Java程序的计算机窗口系统(经常被称作本地窗口系统,native windowing system)底层相结合。AWT组件建立在对等模型(peer model)的基础上。每个AWT组件有一个相应的用本地系统的代码编写的对等类,对等类充当Java代码与本地窗口系统之间的接口,对等类里的方法是用本地代码编写的。例如,若要显示Button类型的对象时,需用java.awt.Button类,它有一个名为java.awt.peer.Button的对等类,在运行微软的Windows 操作系统的计算机上,该Button对象将具有与其它Windows应用程序相同的外观和感觉;同样,在运行Apple公司的Mac OS操作系统的计算机上,该Button对象将具有与其它Macintosh应用程序相同的外观和感觉。因此,AWT组件天生就是平台相关的,AWT组件被认为是重量级组件,它们直接映射到本地组件,需要由本地窗口系统提供资源。注意:本地方法封装了用非Java语言(通常是C或者C+)编写的代码的调用,使JVM的功能获得扩展。Swing组件从根本上来说建立在AWT上,它的四个顶层的窗口类(JApplet, JDialog, JFrame与JWindow)是由AWT重量级组件派生而来,如图7.1所示。它们本身也依赖于本地窗口,除此以外,所有Swing组件都是轻量级组件。Swing的一个显著特点是用Swing实现的图形界面外观可以按需更换,而无需重写任何代码。这就让Swing程序能自动适应于它所运行的计算机的常规风格和外观,不需要程序员为特定的计算机开发特定的界面。事实上,这些外观不限于常见的几种机器,Swing可以开发新的外观风格。Swing中内置了几个观感包。例如,javax.swing.plaf.motif包里有实现Motif界面的类。Motif界面是一种常用的基于UNIX的界面。这些类知道如何画出每个组件,也知道如何响应鼠标、键盘以及其它和这些组件联系在一起的事件。javax.swing.plaf.windows包则负责实现Windows风格的界面。Java缺省的设计风格是“Java外观”(被称为“Metal”),它独立于任何一种窗口系统的Java外观。图7.1 AWT与Swing顶层窗口类之间的关系Swing改善了AWT包没有弹性、缺乏效率的缺点,提供了更丰富的视觉感受,人们越来越多地使用Swing组件构建图形用户界面,在本书中给出的有关GUI程序中均使用Swing组件。7.1.2 Swing组件轻量级组件不是依靠本地组件来支持它的显示,而是完全由Java代码来绘制并显示。Swing平台无关的观感,是通过把所有负责画出一个组件的代码从组件中抽出来形成一个单独的类而实现的。例如,除了定义按钮控件的JButton类之外,还有一个单独的类负责把按钮在屏幕上画出来。画图的这个类将控制按钮的颜色、形状以及其它外面上的特征。构建轻量级组件的一种方法是扩展抽象的java.awt.Component 类,然后改写它的paint()方法:public class LightWeightButton extends Componentpublic void paint(Graphics g)/*在此写绘制组件的Java代码*/抽象类JComponent是能够出现在屏幕上的大多数组件的父类。Java GUI的基本组件都是JComponent类的子类,因此,每个组件都继承了JComponent的所有方法和数据字段。JComponent直接从Container类派生而来,它和它的所有Swing子类都是轻量级组件(见图7.2)。图7.2 Swing部分轻量级组件Swing提供了若干包,在程序中,若使用Swing必须导入javax.swing包。swing包是Swing提供的最大包,它包含将近100个类和25个接口,几乎所有的Swing组件都在swing包中。Swing组件从功能上可分为容器组件和原子组件。又可细分为:顶层容器、中间层容器、特殊容器、基本组件、不可编辑组件以及可编辑组件,如表7.1所示。原子组件必须加在容器组件中,容器组件用来容纳其它容器组件或原子组件,并在其可视区域内显示这些组件。以下称容器组件为容器,原子组件为组件。表7.1 Swing组件分类表GUI类别组件Swing类名基本组件按钮JButton, JCheckBox, JRadioButton组合框JComboBox列表JList菜单JMenu, JMenuBar, JMenuItem, JPopupMenu滑块JSlider工具栏JToolBar文本区JTextField, JPasswordField, JTextArea, JFormattedTextField不可编辑的显示组件标签JLabel工具提示JToolTip进度条JProgressBar可编辑的显示组件表JTable文本JTextPane, JEditorPane树JTree颜色选择器JColorChooser文件选择器JFileChooser数值选择器JSpinner顶层容器窗体JFrame,JWindowappletJApplet对话框JDialog,JOptionPane中间层容器面板JPanel滚动窗格JScrollPane, JScrollBar拆分窗格JSplitPane索查标签窗格JTabbedPane特殊容器内部窗体JInternalFrame分层窗格JLayeredPane根窗格JRootPane7.1.3 Swing容器AWT中的Container类是容器组件的超类,其目的是容纳其它若干组件。一个窗口实际上指的是屏幕上的一个矩形区域,允许程序员将若干独立的组件作为一个整体处理。我们不能直接显示组件,而是需要把它们加到容器中,由容器进行显示。容器也提供一些方法,用于获取和设置许多属性、增加和从自身中删除组件等。在屏幕上显示容器之前,必须调用容器的pack()方法,或者设置其初始尺寸。设置尺寸时可以使用容器的setSize方法:public void setSize(int width,int height)其中的参数以像素(屏幕上的点)为单位。由于轻量级组件和重量级组件之间的差别,为使轻量级组件能够正确地工作,必须使用Swing容器容纳Swing组件。Swing容器按其用途分为顶层容器、中间层容器以及特殊容器。顶层容器(Top Level Container)是一个窗口容器对象,在这样的一个对象里可以再加入其它的窗口对象。JFrame、JApplet、JDialog、JWindow等就可以作为顶层容器,其余的Swing组件都必须依附在此四组件之一上才能显示出来。容器本身具有层次性,每一层都是一种特殊容器,这些特殊容器实际上是在GUI上起特殊作用的中间层。Swing容器具有获取和调整这些面板层的方法。在简单编程过程中主要涉及到将组件加到容器的内容面板中。Swing容器的层次结构如图7.3所示。JFrame JDialog JApplet JWindowJLayeredPaneJRootPaneJContentPaneJGlassPaneJMenuBar图7.3 Swing容器层次结构(1) 根面板JRootPane根面板是顶层容器中所包含的最内层,四个顶层容器均实现RootPaneContainer这个接口,此接口定义了各种容器取得与设置。根面板并不是真实的容器,它是由层次面板(JLayeredPane)与玻璃面板(JGlassPane)所组成,不能在JRootPane上加入任何的组件,因为它只是一个虚拟的容器,通常无法在这一层做操作与处理。若要在最上层组件上加入组件,必须加在JLayeredPane或是JLayeredPane里的内容面板上。需要注意的是,只有顶层容器才有根面板,其它中间层容器没有根面板。(2) 层次面板JLayeredPaneJLayeredPane用于管理JMenuBar和内容面板JContentPane,并维护一个层次叠放顺序(Z-order)标记数据,可以对加入在层次面板中的对象设定层次,而不会被内容面板中的对象屏蔽。一般程序会提供良好的Z-order自动管理机制,当然java也不例外,大部分情况我们不会使用到Z-order,因为系统会自动帮我们管理好。用户只需将所需的组件直接加入内容面板即可,不需要知道它们之间的顺序关系。JMenuBar是一个对象,用于跟踪与容器相关联的任何菜单。JMenuBar是可选的,如果没有,内容面板就会充满整个顶层容器。(3) 内容面板JContentPane与AWT组件不同,Swing组件不能直接添加到顶层容器中,它必须添加到顶层Swing容器的内容面板(JContentPane)上。JContentPane是Swing容器中一个对象,可以把Swing组件加到其中,并设置布局策略。大部分的可视对象都放在内容面板中,一般在程序中必须用getContentPane()方法来获取内容面板,然后将其加到这一层中。内容面板是顶层容器包含的一个普通容器,它是一个轻量级组件,应避免在其上添加非Swing的重量级组件。(4) 玻璃面板JGlassPane在玻璃面板这一层次上主要用来产生绘图效果,以及触发窗口程序的各种事件。 中间层容器主要有JPanel、JScrollPane、JSplitPane、JTabbedPane等,它们没有根面板,不能在桌面上浮动,必须填加到顶层容器中才能显示。下面介绍一些常用的Swing容器。1框架窗口JFrame窗口是最基本的用户界面元素。框架窗口是一种窗体,其中带有边框、标题栏及用于关闭和最大/最小化窗口的图标等。在GUI的应用程序中,一般至少应使用一个框架窗口。通常将框架窗口简称为窗口。JFrame类是由Container类派生而来的,是一种顶层容器类,可用于创建框架窗口。JFrame作为最顶层容器存在,不能被其它容器所包含。它可将加到其内容面板的组件显示在屏幕上,每个加到窗口中的组件需要明确它的大小和位置,以及在窗口中如何显示。JFrame构造方法主要有:JFrame(),建立一个无标题的JFrame。JFrame(String title),建立一个标题为title的JFrame。窗口的基本操作:(1) 创建窗口直接生成一个JFrame类的实例即可建立一个窗口,或通过继承JFrame类来定义子类,再建立窗口。例如,创建一个无标题的窗口,语句如下:JFrame frame=new JFrame();(2) 设置标题通过super(String title)调用基类的构造方法,或通过setTitle(String title)方法来设置窗口标题。例如:JFrame frame=new JFrame(“JFrame testing”);或者:JFrame frame=new JFrame();frame.setTitle(“JFrame testing”);(3) 设置初始位置通过setLocation(int x,int y)方法设置窗口初始位置。其中x,y是窗口左上角在屏幕上的坐标值。(4) 设置大小通过setSize(int width,int height)方法设置窗口初始大小。(5) 设置图标通过setIconImage(Icon icon)方法设置窗口图标。(6) 定义关闭行为通过setDefaultCloseOperation(int operation)方法设置窗口关闭行为。其中operation的取值可以是以下几种:DO_NOTHING_ON_CLOSE:当窗口关闭时,不做任何处理;HIDE_ON_CLOSE:当窗口关闭时,隐藏这个窗口;DISPOSE_ON_CLOSE:当窗口关闭时,隐藏并处理这个窗口;EXIT_ON_CLOSE:当窗口关闭时,退出程序。operation默认值是HIDE_ON_CLOSE。(7) 添加组件创建好Jframe之后,就可以向它的内容面板中添加组件。对Jframe添加组件有两种方式:第一种方式,用getContentPane( )方法获得JFrame的内容面板,再对其加入组件,语句如下:frame.getContentPane().add(childComponent)第二种方式,先建立一个JPanel或 JDesktopPane之类的中间容器,把组件添加到容器中,用窗口对象的setContentPane()方法把该容器置为JFrame的内容面板:JPanel conPane=new JPanel(); / 把其它组件添加到JPanel中frame.setContentPane(conPane); /把conPane对象设置成为窗口对象frame的内容面板 这里需要注意的是,Swing容器都可以用来容纳其他组件,但除了JPanel及其子类可以直接添加组件以外,其它Swing容器都不允许把组件直接加进去,添加方法和JFrame中添加组件一样。【例7.1】 建立一个标题为“Swing窗口”,大小为(300,200),图标为javalogo.gif,位置居中的窗口。屏幕效果如图7.4所示。图7.4 Swing窗口源程序如下:/JFrameDemo.javaimport javax.swing.*;import java.awt.*;public class JFrameDemo extends JFrame / 定义一个窗口子类 JFrameDemo() setIconImage(new ImageIcon(javalogo.gif).getImage(); / 设置图标setSize(300,200); / 设置窗口大小setTitle(Swing窗口); / 设置窗口标题/ 取得屏幕尺寸Dimension screen=Toolkit.getDefaultToolkit().getScreenSize();Dimension mySize=this.getSize(); / 取得窗口尺寸/设置初始位置于屏幕中央setLocation(screen.width-mySize.width)/2,(screen.height-mySize.height)/2); setVisible(true); / 使窗口可见 public static void main(String args) JFrameDemo myFrame=new JFrameDemo(); / 创建窗口myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); / 设置关闭行为 2. 无边框的窗口JWindowJWindow可以构造无边框的窗口。主要构造方法有:JWindow():创建一个无边界的窗口;JWindow(Frame owner):创建一个依赖Frame对象的窗口。3对话框JDialog 对话框与框架窗口类似,是有边框、有标题、可独立存在的顶级容器。对话框分为无模态对话框和模态对话框。模态对话框只让程序响应对话框内部的事件,对于对话框以外的事件程序不响应,并且在该对话框被关闭之前,其他窗口无法接受任何形式的输入;而无模态对话框可以让程序响应对话框以外的事件,没有限制。JDialog的构造方法有:JDialog(Frame owner);JDialog(Frame owner,Boolean modal);JDialog(Frame owner,String title);JDialog(Frame owner,String title,Boolean modal);其中,参数owner指明对话框隶属哪个窗口,参数title指明对话框的标题。参数modal为true时,指明对话框是模态的;如果modal为false,则指明对话框是无模态的。用JDialog来作对话框,必须实现对话框中的每一个组件,但有时候对话框只要显示一段文字,或是作一些简单的选择,这时候可以利用JOptionPane类,从而大大的减少了程序代码的编写。JOptionPane类也在javax.swing包内。要利用JOptionPane类来输出对话框,通常不使用new创建一个JOptionPane对象出来,而是使用JOptionPane所提供的一些静态方法,这些方法都是以showXxxxxDialog的形式出现。例如,建立一个消息对话框可使用JOptionPane.showMessageDialog();另外,JOptionPane.showConfirmDialog()会建立一个确认对话框,JOptionPane.showInputDialog()会建立一个输入对话框。4面板JPanelSwing的JPanel,它替代了AWT的画布(Canvas)和面板(Panel),兼有二者的功能。JPanel是一个非顶级的通用容器,总是处于其它一些容器中。JPanel不能象JFrame那样能够在桌面上浮动。利用JPanel可以使版面的排列方式更生动,对于复杂GUI,通常由多个面板组成,而每个面板以特定的布局来排列组件。JPanel的构造方法有:JPanel();JPanel(boolean isDoubleBuffered);JPanel(LayoutManager layout);JPanel(LayoutManager layout,boolean isDoubleBuffered);其中,isDoubleBuffered指明是否具有双缓冲,layout指明布局方式。JPanel默认是非双缓冲,布局为流式布局(FlowLayout)。5. 分割面板JSplitPaneJSplitPane一次可将两个组件同时显示在两个显示区中,若想要同时在多个显示区显示组件,便必须同时使用多个JSplitPane。JSplitPane提供两个常数:HORIZONTAL_SPLIT、VERTICAL_SPLIT,用来设置水平分割或是垂直分割。6. JTabbedPane如果一个窗口的功能有几项,可以给每项设置一个标签,每个标签下面包含为完成此功能专用的若干组件。用户要使用哪项功能,只要单击相应的标签,就可以进入相应的页面。这种选项卡功能的实现就需要使用JTabbedPane这个中间层容器。7. 滚动面板JScrollPane当容器内要容纳的内容大于容器时,希望容器能够有一个滚动条,通过拖动滑块,就可以看到更多的内容。JScrollPane就是能够实现这种功能的容器。8. JInternalFrame使用JInternalFrame容器类可以实现在一个主窗口中打开很多个文档,每个文档各自占用一个新的窗口。JInternalFrame的使用跟JFrame几乎一样,可以最大化、最小化、关闭窗口、加入菜单;唯一不同的是JInternalFrame是轻量级组件,它只能是中间容器,必须依附于顶层容器上。7.1.4 基于Swing的Java GUI设计思路构造用户界面会涉及到一些基本概念,包括前面已经提到的组件、容器,还有后面要说明的布局管理器和事件处理等。Java GUI编程,一般可依据下面的设计思路:1. 设置顶层容器。通常是JFrame或Japplet,用于设计Java应用程序或Java小应用程序。2. 创建组件。组件包括按钮、菜单以及选项等。3. 使用某种布局把组件加到某个容器中。对于复杂的用户界面,通常会使用若干中间层容器,这样便于对组件的管理,在编程时先将组件置于中间层容器中,之后再将中间层容器加到顶层容器中。对于组件在容器中的位置和大小,也可交给布局管理器全权负责。4. 实现事件处理程序,以便响应点击按钮、菜单选择、窗口缩放以及其它活动等。7.2 图形与绘图7.2.1 绘图表面为了在Java程序里进行绘图和绘画,需要有一个可以操作的表面。在抽象窗口工具包(AWT)中,这个绘图表面通常是一个Canvas组件。在Swing程序中可以直接在顶层窗口(通常是JApplet和JFrame)上绘图,或者在JPanel的子类上绘图。7.2.2 图形环境和图形对象要在Java中绘图,还需理解Java的坐标系统,如图7.5所示。GUI组件(诸如applet或窗口)的左上角坐标默认为(0,0),坐标对由一个x坐标(水平坐标)和一个y坐标(垂直坐标)组成。x坐标是从左上角向右移动的水平距离,y坐标是从左上角向下移动的垂直距离。坐标的单位是像素,它是显示器分辨率的最小单位。图7.5 以像素为单位的Java坐标系统在屏幕上绘图要使用Java图形环境,每个Java组件(包括Swing组件),都有一个与之关联的图形环境,也称图形上下文,用java.awt.Graphics类的一个对象来表示。Graphics对象用于管理图形环境,并在屏幕上绘制代表文本或其它图形对象(如线条、椭圆、矩形或其它多边形)的像素。Graphics 类是所有图形上下文的抽象基类,这个上下文允许应用程序将图形绘制到由不同设备实现的组件上,以及绘制到空闲屏幕的映像中。 java.awt.Graphics类是一个抽象类,不能直接创建一个Graphics对象,这是由Java的可移植性决定的,因为在支持Java的各个平台上,执行的绘图操作是不同的,例如运行Microsoft Windows的PC机绘制矩形的图形功能不同于UNIX工作站上绘制矩形的图形功能,而且它们也不同于Macintosh系统中绘制矩形的图形功能。在各个平台实现Java时,系统将创建Graphics的一个子类,以实现绘图功能。一个 Graphics 对象封装有 Java 所支持的基本绘图操作所需的状态信息。此状态信息包括下列属性: (1) 要被绘制到其上的组件对象; (2) 绘制和剪贴坐标的平移原点。; (3) 当前的剪贴区; (4) 当前颜色; (5) 当前的字体; (6) 当前的逻辑像素操作函数 (XOR 或 Paint) ; (7) 当前的 XOR 替换颜色。 其中XOR模式称为位异或模式,它符合逻辑操作异或。在XOR模式下,当在背景色和前景色上执行一个异或操作时,像素点的前景色是由画笔的颜色来决定的。在黑白绘图方式下,如果画笔是黑色的,在背景为白色的任何位置,绘图都是黑色的;如果背景已经是黑色的,那么绘图就会是白色的。这样,在这种情况下XOR模式会对背景色进行反色操作。在有颜色的背景下,也能获得类似的效果。Graphics类中定义了许多方法,包含用于改变上述属性默认值的访问方法,以及各种绘图方法,分别如表7.2和表7.3所示。表7.2 Graphics类的部分获取和设置属性默认值的方法名称说明Shape getClip()返回表示当前剪贴区域的 Shape 对象Color getColor()返回该图形上下文的当前颜色Font getFont()返回该图形上下文的当前字体FontMetrics getFontMetrics()返回该图形上下文当前字体的字体度量void setClip(Shapeclip)将当前的剪贴域设置为任意剪贴形状void setColor(Colorc)将该图形上下文的当前颜色设置为指定的颜色void setFont(Fontfont)将指定的字体设置为该图形上下文的字体。void translate(intx,inty)将图形上下文的原点平移到当前坐标系的 (x ,y) 点处。修改该图形的上下文,使得它的新原点与该图形上下文原先坐标系中的 (x,y) 点相一致表7.3 Graphics类的绘图方法方法说明void drawString(String str,int x,int y)使用该图形上下文的当前字体和颜色,从坐标点(x,y)位置处开始绘制由指定的字符串给出的文本void drawLine(intx1,inty1,intx2,inty2)绘制一条在点(x1,y1) 和(x2,y2) 之间的线void drawRect(int x,int y,int width,int height)画一矩形,左上角坐标为(x,y),宽width ,高heightvoid fillRect(int x,int y,int width,int height)绘制一个使用当前颜色填充的指定矩形void clearRect(intx, inty, intwidth, intheight)通过用当前绘图表面的背景颜色填充的方法来清除指定的矩形。void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight)使用当前颜色绘制圆角矩形。圆角是一个椭圆的1/4弧,此椭圆由arcWidth,arcHeight确定两轴长void fillRoundRect(int x, int y, int width,int height, int arcWidth, int arcHeight)用当前颜色填充指定的圆角矩形void draw3DRect(int x, int y, int width, int height, boolean raised)绘制指定矩形的一个突出显示的三维轮廓。raised为true时,该矩形为凸的,反之为凹的void fill3DRect(int x, int y, int width, int height, boolean raised)绘制一个用当前颜色填充的三维矩形void drawOval(int x,int y,int width,int height) 绘制椭圆形的轮廓。结果是一个圆或椭圆,并适合由 x ,y ,width 和 height 参数指定的矩形void fillOval(int x, int y, int width, int height)用当前颜色填充由指定矩形限定的椭圆void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle)绘制一个覆盖指定矩形的圆或椭圆弧的轮廓void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)填充一个覆盖了指定矩形的圆或椭圆弧void drawPolyline(int xPoints,int yPoints,int nPoints)绘制由 x 和 y 坐标数组定义的连接线序列。每对 (x,y)坐标定义一个点void drawPolygon(int xPoints,int yPoints,int nPoints)绘制由 x 和 y 坐标数组定义的闭合多边形。每对 (x,y) 坐标定义一个点void drawPolygon(Polygon p)绘制由指定的 Polygon 对象定义的多边形的轮廓void fillPolygon(int xPoints,int yPoints, int nPoints)填充由 x 和 y 坐标数组定义的闭合多边形void fillPolygon(Polygon p)用图形上下文的当前颜色填充由指定的 Polygon 对象定义的多边形。多边形内的区域使用奇偶填充规则和交替填充规则来定义boolean drawImage(Image img, int x,int y, ImageObserver observer)绘制指定图像的当前可用部分。绘制的图像,其左上角位于坐标(x,y) 位置。如果图像没有被完全装入,那么 drawImage 方法将返回 false7.2.3 颜色颜色美化了程序的外观,并有助于信息的表达。Java的颜色是根据RGB值来建立的,RGB值是用于指定红色、绿色和蓝色量的3个数字的组合,这些颜色组件混合在一起形成了最终的颜色。java.awt.Color类声明了用于操作Java程序中颜色的方法,同时Color类定义了一些标准颜色,作为类常量使用,这些常量共有13个,它们的名称有小写名称也有大写名称,表7.4中采用大写形式,这样符合常量的命名约定。表7.5给出了一些Color类的构造函数和常用方法。表7.4 Color类的常量颜色常量颜色public final static Color BLACK黑色public final static Color BLUE蓝色public final static Color CYAN蓝绿色public final static Color DARKGRAY深灰色public final static Color GRAY灰色public final static Color GREEN绿色public final static Color LIGHT_GRAY浅灰色public final static Color MAGENTA紫红色public final static Color ORANGE橙色public final static Color PINK粉红色public final static Color RED红色public final static Color WHITE白色public final static Color YELLOW黄色表7.5 Color类的方法方法说明Color(int r,int g,int b)用指定的红、绿和蓝色成分创建一个颜色。三个参数都必须在 0-255 范围内Color(int rgb)用指定的 RGB 值创建一个颜色,其中参数的 16-23 位表示红色成分,8-15 位表示绿色成分,0-7 位表示蓝色成分。0 表示这个基色成分没有参与颜色构成Color(float r, float g, float b)用指定的红、绿和蓝色值创建一个颜色,其中每个值在 0.0-1.0 范围内。0.0 值表示这个基色成分没有贡献。值 1.0 表示这个基色成分的最大饱和度int getRed()获取这个颜色的红色成分。返回结果是一个0 - 255 之间的整数int getGreen()获取这个颜色的绿色成分。返回结果是一个 0 - 255 之间的整数int getBlue()获取这个颜色的蓝色成分。返回结果是一个 0 - 255 之间的整数设计使用颜色的程序时必须要小心,因为颜色的表示是与系统有关的。在理论上讲,可能指定256*256*256=16 777 216种不同的颜色。但是在实际系统中,真正能够显示的不同颜色的数目,取决于系统显示器的质量。如果显示只允许使用8位颜色来表示每个像素,则最多可以表示28=256种颜色,在这种情况下,操作系统会决定显示16 777 216种颜色中的哪256种颜色,如果程序需要这256种颜色之外的颜色,系统会选择最相近的颜色。7.2.4 字体为了创建有吸引力的界面,常常需要选择和控制所用的字体。Java中有关字体控制的类是Font类,有关字体度量的类是FontMetrics,它们都在java.awt包中。前面已经提到,每个图形上下文都有一个相关的字体Font对象和字体度量FontMetrics对象,Font对象包括字体名、字号和风格等属性,FontMetrics对象封装了字体的许多重要数据,如字体的高度和宽度等。表7.6给出了Font类的一些常量和常用方法。表7.6 Font类的方法和常量常量或方法说明public final static int PLAIN一个代表普通字体风格的常量public final static int BOLD一个代表粗体字体风格的常量public final static int ITALIC一个代表斜体字体风格的常量Font(String name,int style,int size)利用指定的字体、风格和大小创建一个Font对象int getStyle()返回一个表示当前字体风格的整数值int getSize()返回一个表示当前字体大小的整数值String getName()以字符串形式返回当前字体名称String getFamily()以字符串形式返回当前字体族名称Boolean isPlain()测试一个字体是否是普通字体风格Boolean isBold()测试一个字体是否是粗体字体风格Boolean isItalic()测试一个字体是否是斜体字体风格Font类的构造函数有3个参数:字体名称、字体风格和字体大小。字体名称可以是运行程序的当前系统所支持的任何字体,在Java1.1和以后的版本中,所支持的字体名字有Monospaced、SansSerif、Serif、Dialog和DialogInput。字体风格可以是表7.6已列出的三个之一,也可以是Font.ITALIC+Font.BOLD组合。字体大小以磅为度量单位,一磅等于1/72英寸。这些名字和风格是平台无关的,当用于程序中时,会映射成本地系统可用的实际字体。如果本地系统没有与指定字体确切相匹配的字体,就会提供一个替代字体。7.2.5 使用Graphics类绘图当在AWT组件和Swing顶层窗口(JApplet和JFrame,是java.awt.Component的子类)上绘图时,需要重写组件的paint()方法;当在Swing的JComponent的子类组件上绘图时,则需重写paintComponent()方法。在这两种情况(Swing和AWT)下,都是以一个Graphics对象作为参数。在某个组件需要进行绘图操作时,系统会将Graphics对象传递给paint方法或paintComponent方法。paint方法和paintComponent方法的头部分别为:public void paint(Graphics g )public void paintComponent(Graphics g )程序员很少直接调用paint方法,因为绘制图形是一个事件驱动过程。在执行applet(在第九章对此进行详细说明)时,applet的容器调用paint方法,要再次调用paint方法,必须产生一个事件(如隐藏或重新显示applet的窗口)。类似地,在显示任何组件对象时,将调用该组件对象的paint方法。如果程序员需要强制执行paint方法,一般是调用repaint()方法(此方法不应重写,因为该方法执行一些与系统相关的任务),该方法自动调用Component类的update(Graphics g)方法以清除Component背景中的旧图,然后update方法直接调用paint方法。【例7.2】 使用各种颜色绘制文字及各种图形。屏幕效果如图7.6所示。源程序如下:/ Graphic.javaimport java.awt.*;import javax.swing.*;public class Graphic extends JFramepublic Graphic()super(字体、颜色与绘图示例); / 调用超类的构造方法,设置窗口标题setSize(480,240); / 设置窗口大小setVisible(true); / 使窗口可见public void paint(Graphics g) / 重写paint方法super.paint(g);g.setFont(new Font(Serif,Font.BOLD,12);/*设置图形环境的字体,名为Serif,黑体,12号*/g.setColor(Color.BLACK); / 设置颜色g.drawString(字体Serif,粗体,12号,黑色,20,50); / 绘制字符串g.setFont(new Font(SansSerif,Font.BOLD+Font.ITALIC,15);g.setColor(new Color(255,0,0);g.drawString(字体SansSerif,粗斜体,15号,红色,200,50);g.drawLine(20,60,450,60); / 绘制直线g.setColor(Color.BLUE);g.drawRect(20,70,100,50); / 绘制矩形g.fillRect(130,70,100,50); / 绘制实心矩形g.setColor(Color.YELLOW);g.draw3DRect(20,130,100,50,true); / 绘制三维凸起矩形g.fill3DRect(130,130,100,50,false); / 绘制三维凹陷实心矩形g.setColor(Color.pink);g.drawOval(240,80,100,50); / 绘制椭圆g.fillOval(350,80,100,50); / 绘制实心椭圆g.setColor(Color.MAGENTA);int xValues=250,280,290,300,330,310,320,290,260,270;int yValues=160,160,140,160,160,170,180,170,180,170;g.drawPolygon(xValues,yValues,10); / 根据给定的10个坐标点,绘制空心多边形int xValues2=360,390,400,410,440,420,430,400,370,380;g.fillPolygon(xValues2,yValues,10); / 根据给定的10个坐标点,绘制实心多边形public static void main(String args) / 设置窗口的外观和感觉为Java默认JFrame.setDefaultLookAndFeelDecorated(true); Graphic myGraphic=new Graphic(); / 产生Graphic类的一个实例myGraphic.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); / 关闭窗口图7.6 使用Graphics类绘图7.3事件处理与Swing常用组件声明组件、处理事件以及将组件置于容器内这三个问题联系得非常紧密,在后续小节中我们将分别进行说明,而在所有基于GUI的程序中,其核心是事件处理,下面对此先进行说明。GUI是事件驱动的(即用户与GUI进行交互时,GUI将产生事件)。一些常见的事件包括单击鼠标按钮、移动鼠标、单击按钮、在文本字段内进行输入、在菜单中选择菜单项、关闭窗口等。若发生了一次用户交互,就将一个消息发送给程序。GUI事件信息存储在扩展AWTEvent的类的一个对象中。AWT组件和Swing组件都可以使用java.awt.event包中的事件类型。javax.swing.event包还声明了其它一些事件类型,这些事件类型是专用于Swing组件的。7.3.1 Java事件处理机制事件处理机制是一种事件处理框架,其设计目的是把GUI交互动作(鼠标点击、菜单选择等)转变为调用相关的事件处理程序进行处理。JDK1.1以后Java采取了授权处理机制(Delegation-based Model),事件源可以把在其自身所有可能发生的事件分别授权给不同的事件处理者来处理。由于窗口管理器无法直接调用开发人员提供的事件处理程序,必须在运行时告诉事件模型,哪一个例程用于处理事件。因此,为了获取任何事件,开发人员必须事先通知窗口系统,令其将事件发送给自己提供的事件处理程序,把事件处理程序注册为窗口管理器中的一个回调例程,使之连接到产生事件的组件上。要实现这个过程,就要用到事件处理机制中的三个对象:事件源、事件对象和事件监听器。事件源是与用户进行交互的特定组件。事件源提供注册监听器或取消监听器的方法,它维护一个已注册的监听器列表,如有事件发生,就会通知每个已注册的监听器。一个事件源可以注册多个事件监听器。事件对象封装了有关已发生的事件的信息,这些信息包括事件源的一个引用和事件专用信息,事件监听器需要这些信息来处理事件。事件监听器也是一个对象,该对象所属的类实现了java.awt.event或javax.swing.event包中的一个或多个事件监听器的接口。每个监听器可以对多种事件进行响应。事件监听器负责监听事件,它监视所有事件类型,当有事件发生时,事件监听器会接收到事件源产生的事件对象,一旦该事件类型与自己所负责处理的事件类型一致,就会以该事件对象作为参数自动调用相应的事件处理程序作出响应。许多事件监听器类型是Swing组件和AWT组件所共有的。这样的事件监听器类型声明在java.awt.event包中,并且其中许多都显示在表7.7中。不同的组件会产生不同的事件,不同的事件处理程序要实现不同的接口,表7.7概括了三者之间的关系。每个接口所承诺的方法可查阅Java doc的API。表7.7 类别、事件与接口一般类别产生的事件事件处理程序实现的接口鼠标拖曳、移动鼠标产生的MouseEvent,点击、选择、释放鼠标引起的MouseEventMouseMotionListenerMouseListener鼠标滚轮鼠标滚轮事件MouseWheelListener键盘按键或释放产生的KeyEventKeyListener选择(列表、复选框等的某一项)选择某一选项时产生的ItemEventItemListener文本输入组件输入换行符时产生的TextEventTextListener滚动控件滚动条滑动时引起的AdjustmentEventAdjustmentListener其它组件(按钮、菜单等)点击组件时或文本框中按下Enter键时产生的ActionEventActionListener窗口变动打开、关闭窗口以及把窗口缩小为图标时产生的WindowEventWindowListener键盘焦点变动使用制表键转到下一个字段,或者要求聚焦时引起的FocusEvent。组件必须在获得聚焦时才能产生事件FocusListener组件变动缩放、隐藏、显露或移动组件时产生的ComponentEventComponentListener容器变动加入或撤销容器中的组件引起的ContainerEventContainerListener要使程序能够处理图形用户界面的事件,程序员必须完成2项关键任务:为产生事件的GUI组件注册一个事件监听器;实现一个事件处理方法(或一组事件处理方法)。事件处理方法通常称为事件处理程序。下面以“关闭窗口”事件为例,来说明Java事件处理框架。 【例7.3】 关闭窗口事件处理。源程序如下:/ CloseDemo1.javaimport javax.swing.*;import java.awt.event.*;public class CloseDemo1public static void main(String args)JFrame jframe=new JFrame(关闭窗口例);/ 创建一个窗口jframe.setSize(400,100); / 设置窗口大小jframe.setVisible(true); / 使窗口可见myWinClose handler=new myWinClose();
展开阅读全文