最新图形用户界面设计概述PPT课件.ppt
9.1图形用户界面设计概述图形用户界面设计概述v 9.1.1 GUI支持包和简单GUI程序例v 1.java.awt包 v Java语言在java.awt包中提供了大量地进行GUI设计所使用的类和接口,包括绘制图形、设置字体和颜色、控制组件、处理事件等内容,AWT是Java语言进行GUI程序设计的基础。v 2. javax.swing包v Swing包是Java基础类库(Java Foundation Classes,JFC)的一部分。Swing提供了从按钮到可分拆面板和表格的所有组件。v 由于Swing组件使用AWT的结构,包括AWT的事件驱动模式,所以,使用swing组件的程序一般需要使用awt包。v (2)使用缺省的观感或设置自己的观感(Look and Feel)v (3)设置一个顶层的容器v (4)根据需要,使用缺省的布局管理器或设置另外的布局管理器v (5)定义组件并将它们添加到容器v (6)对组件或事件编码v 9.1.2 容器、组件、布局和观感v 1.容器(Container)和组件(Component)v 一个Java的图形用户界面的最基本元素是组件,组件是可以以图形化的方式显示在屏幕上并能与用户进行交互的对象,如一个按钮、一个文本框等。在Java语言中,通常将组件放在一定的容器内使用。容器实际上是一种具有容纳其他组件和容器的功能的组件。抽象类Container是所有容器的父类,其中包含了很多有关容器的功能和方法。而类Container又是Java语言的组件类Component的子类。v 2.布局管理器(Layout Manager)v 为了使得图形用户界面具有良好的平台无关性,在Java语言中提供了布局管理器这个工具来管理组件在容器中的布局,而不使用直接设置组件位置和大小的方式。容器中的组件定位由布局管理器决定。每个容器都有一个缺省的布局管理器,当容器需要对某个组件进行定位或判断其大小尺寸时,就会调用其相应的布局管理器。但也可以不用缺省的布局管理器,在程序中指定其新的布局管理器。v Java平台提供多种布局管理器,常用的有FlowLayout、BorderLayout、 GridLayout、CardLayout、BoxLayout和GridBagLayout等。使用不同的布局管理器,组件在容器上的位置和大小都是很不一样的。 v 在程序中安排组件的位置和大小时,应该注意:v (1)容器中的布局管理器负责各个组件的大小和位置。因此用户无法在这种情况下直接设置这些属性。若试图使用Java语言提供的setLocation()、setSize()、setBounds()等方法,则都会被布局管理器覆盖。v (2)若用户确实需要亲自设置组件的位置和大小,则应取消该容器的布局管理器,方法为: setLayout(null); setLayout(null);v 随后,用户必须使用setLocation()、setSize()、setBounds()等方法为组件设置大小和位置,但这种方法将会导致程序的系统相关。v 在一个GUI应用程序的界面上,除了可以见到上述的标准GUI元素外,还可以见到一些非交互的起到装饰、美化界面的作用的几何图形、图案、图像等内容。v 3.观感(Look and Feel)v Java swing的一个重要特征是它的可插入的“观感”体系。一个Swing应用程序或一个最终用户可指明所需要的观感,使得Swing应用程序的外观和行为都可以被定制。Swing运行一个缺省的Java观感(也称为Metal观感),还实现了模仿Motif和Windows的观感。这样,一个Swing程序可拥有Java程序的独特外观,也可以拥有熟悉的Windows操作系统外观。v 在本章稍后部分的单选按钮的程序例中分别显示了Windows、Motif和Metal三种不同风格的观感。v 一般在应用程序的JFrame的构造方法中或在JApplet的init()方法中进行观感的设置。v 【例9.2】设置观感。 import javax.swing.import javax.swing.* *; ; import java.awt.import java.awt.* *; ; public class SetLAFpublic class SetLAF public static void setNativeLookAndFeel() public static void setNativeLookAndFeel() try try UIManager.setLookAndFeel(UIManager. UIManager.setLookAndFeel(UIManager. getSystemLookAndFeelClassName(); getSystemLookAndFeelClassName(); catch(Exception e) catch(Exception e) System.out.println( System.out.println(设置设置native LAFnative LAF错误错误: : + + e);e); public static void setJavaLookAndFeel() public static void setJavaLookAndFeel() try try UIManager.setLookAndFeel(UIManager. UIManager.setLookAndFeel(UIManager. getCrossPlatformLookAndFeelClassName(); getCrossPlatformLookAndFeelClassName(); catch(Exception e) catch(Exception e) System.out.println( System.out.println(设置设置Java LAFJava LAF错误错误: + : + e);e); public static void setMotifLookAndFeel() public static void setMotifLookAndFeel() try try UIManager.setLookAndFeel(“ UIManager.setLookAndFeel(“ com.sun.java.swing.plaf. com.sun.java.swing.plaf. motif.MotifLookAndFeel); motif.MotifLookAndFeel); catch(Exception e) catch(Exception e) System.out.println( System.out.println(设置设置Motif LAFMotif LAF错误错误: + : + e);e); v 因为因为setLookAndFeelsetLookAndFeel()方法抛出异常,因此设置观感的代码应捕捉异常。本例创建的类SetLAF可在以后的程序中设置观感时使用。v 9.1.3事件处理v 在一个GUI程序中,为了能够接收用户的输入、命令的按键和鼠标操作,程序系统首先应该能够识别这些操作并做出相应的响应。通常一个键盘和鼠标操作将引发一个系统预先定义好的事件,用户程序只要编写代码定义每个事件发生时程序应做出何种响应即可。这些代码会在它们对应的事件发生时由系统自动调用,这就是GUI程序中事件和事件响应的基本原理。v 在Java语言中,除了键盘和鼠标操作,系统的状态改变也可以引发事件。v 可能产生事件的组件称为事件源,不同事件源上发生的事件种类是不同的。若希望事件源上引发的事件被程序处理,需要将事件源注册给能够处理该事件源上那种事件类型的监听器。监听器具有监听和处理某类事件的功能,它可以是包容事件源的容器,也可以是另外的对象。也就是说,事件源和事件处理是分开的,一般组件都不处理自己的事件,而将事件处理委托给外部的处理实体,这种事件处理模型称为授权处理模型。v 事件的行为多种多样,由不同的监听器处理。编写事件处理程序首先应确定关注的事件属于何种监听器类型。 v 在AWT中,提供11种标准的监听器类型,见下表。 监听器 适配器类 注册方法 ActionListener addActionListener AdjustmentListener addAdjustmentListener ComponentListener ComponentAdapter addComponentListener ContainerListener ContainerAdapter addContainerListener FocusListener FocusAdapter addFocusListener ItemListener addItemListener KeyListener KeyAdapter addKeyListener MouseListener MouseAdapter addMouseListener MouseMotionListener MouseMotionAdapter addMouseMotionListener TextListener addTextListener WindowListener WindowAdapter addWindowLv 在确定监听器类型后,要用事件源类的注册方法来注册一个监听器类的对象。这样,事件源产生的事件会传送给已注册的处理该类事件的监听器对象,该对象将自动调用相应的事件处理方法来处理该事件。具体的注册方法是:用监听器类的对象作为参数调用事件源本身的addXxxListener()方法。该方法的参数是一个监听器类的对象,有多种形式。例如: (1)(1)分离的监听器类,该类通常为继承相应事件适配器类的子类,分离的监听器类,该类通常为继承相应事件适配器类的子类,类中包含了事件处理方法。参数是该类的一个对象。类中包含了事件处理方法。参数是该类的一个对象。 (2)(2)实现监听器接口,参数为实现监听器接口,参数为thisthis,表示本对象就是一个监听器类表示本对象就是一个监听器类的对象。在本类中包含事件处理方法。的对象。在本类中包含事件处理方法。 (3)(3)有名内部类,参数形式为继承事件适配器类的子类对象,在子有名内部类,参数形式为继承事件适配器类的子类对象,在子类中包含事件处理方法。类中包含事件处理方法。 (4)(4)匿名内部类,参数形式为用匿名内部类,参数形式为用newnew开始的一个无名的类定义。其中开始的一个无名的类定义。其中包含事件处理方法。包含事件处理方法。9.2布局管理器布局管理器v 在容器中所有组件的布局(位置和大小)由布局管理器来控制。在Java语言中提供了FlowLayout、BorderLayout、GridLayout、CardLayout和GridBagLayout等多种布局管理器。v 每种容器都有自己缺省的布局管理器。缺省地,JPanel使用FlowLayout,而内容窗格 ContentPanev (JApplet、JDialog和JFrame对象的主容器) 使用BorderLayout。如果不希望使用缺省的布局管理器,则可使用所有容器的父类Container的setLayout()方法来改变缺省的布局管理器。 v 1.FlowLayoutv FlowLayout布局是一种最基本的布局。这种布局指的是把组件一个接一个从左至右、从上至下地依次放在容器上,每一行中的组件缺省为居中对齐。当容器的尺寸改变后,组件的大小不变,但布局将会随之变化。v FlowLayout是Applet和JPanel的缺省布局管理器。FlowLayout类的构造方法如下: FlowLayout() FlowLayout() 创建每行组件对齐方式为居中对齐、组件间距为创建每行组件对齐方式为居中对齐、组件间距为5 5个像素单位的对象个像素单位的对象 FlowLayout(int align) FlowLayout(int align) 创建指定每行组件对齐方式、组件间距创建指定每行组件对齐方式、组件间距为为5 5个像素单位的对象,个像素单位的对象,alignalign可取三个静态常量可取三个静态常量LEFTLEFT、CENTERCENTER和和RIGHTRIGHT之一(分别表示左、中、右对齐方式)之一(分别表示左、中、右对齐方式)。 FlowLayout(int align, int hgap, int vgap) FlowLayout(int align, int hgap, int vgap) 创建指定每行组创建指定每行组件对齐方式的对象,该对象也使用参数件对齐方式的对象,该对象也使用参数vgapvgap和和hgaphgap指定了组件间指定了组件间的以像素为单位的纵横间距。的以像素为单位的纵横间距。v 向使用FlowLayout布局的容器添加组件可简单地使用下面的语句: add(add(组件名组件名););v 2BorderLayoutv BorderLayout 是内容窗格的缺省布局管理器。内容窗格是框架JFrame,小程序JApplet和对话框JDialog的主容器。BorderLayout将容器的布局分为五个区:北区、南区、东区、西区和中区。这几个区的分布规律是“上北下南,左西右东”。当容器的大小改变时,容器中的各个组件相对位置不变,其中间部分组件的尺寸会发生变化,四周组件宽度固定不变。v BorderLayout类的构造方法如下: BorderLayout() BorderLayout() 创建组件间无间距的创建组件间无间距的BorderLayoutBorderLayout对象。对象。 BorderLayout(int hgap, int vgap) BorderLayout(int hgap, int vgap) 创建有指定组件间距的创建有指定组件间距的对象。对象。v 向BorderLayout布局的容器添加组件时,每添加一个组件都应指明该组件加在哪个区域中。add()方法的第二个参数指明加入的区域,区域东南西北中可用五个静态常量表示:BorderLayout.EAST、BorderLayout.SOUTH、BorderLayout.WEST、BorderLayout.NORTH和BorderLayout.CENTER。v 【例9.3】将五个按钮加入BorderLayout的五个区。 import java.awt.import java.awt.* *; ; import javax.swing.import javax.swing.* *; ; public class BorderLayoutDemo extends JApplet public class BorderLayoutDemo extends JApplet public void init() public void init() Container c = getContentPane(); Container c = getContentPane(); c.add(new Button( c.add(new Button(北北North), BorderLayout.NORTH);North), BorderLayout.NORTH); c.add(new Button( c.add(new Button(南南South), BorderLayout.SOUTH);South), BorderLayout.SOUTH); c.add(new Button( c.add(new Button(东东East), BorderLayout.EAST);East), BorderLayout.EAST); c.add(new Button( c.add(new Button(西西West), BorderLayout.WEST);West), BorderLayout.WEST); c.add(new Button( c.add(new Button(中中Center), BorderLayout.CENTER);Center), BorderLayout.CENTER); v 程序运行的结果见下图。v3GridLayoutvGridLayout布局是将容器的空间分成若干行和列的一个个网格,可以给出网格的行数和列数,组件添加到这些网格中。当改变容器的大小后,其中的组件相对位置不变,但大小改变。容器中各个组件同高度、同宽度。各个组件缺省的排列方式为:从上到下,从左到右。v GridLayout类的构造方法如下: public GridLayout()public GridLayout()创建单行每个组件一列的创建单行每个组件一列的GridLayoutGridLayout对象。对象。 public GridLayout(int rows, int cols) public GridLayout(int rows, int cols) 创建指定行列数的创建指定行列数的GridLayoutGridLayout对象。对象。 public GridLayout(int rows, int cols, int hgap, int vgap)public GridLayout(int rows, int cols, int hgap, int vgap)创建指定行列数的创建指定行列数的GridLayoutGridLayout对象。对象。v 因为没有容器缺省使用GridLayout,因此在使用GridLayout前,要用setLayout()方法将容器的布局管理器设置为GridLayout。v 在向GridLayout添加组件时,组件加入容器要按序进行,每个网格中都必须加入组件,若希望某个网格为空,可以为该网格加入一个空的标签:add(new JLabel()。v 【例9.4】GridLayout布局。 import java.awt.import java.awt.* *; ; import javax.swing.import javax.swing.* *; ; public class GridLayoutDemo extends JApplet public class GridLayoutDemo extends JApplet public void init() public void init() Container c = getContentPane(); Container c = getContentPane(); c.setLayout(new GridLayout(3,2); c.setLayout(new GridLayout(3,2); c.add(new Button(1); c.add(new Button(1); c.add(new Button(2); c.add(new Button(2); c.add(new Button(3); c.add(new Button(3); c.add(new Button(4); c.add(new Button(4); c.add(new Button(5); c.add(new Button(5); c.add(new Button(6); c.add(new Button(6); v 4.CardLayoutvCardLayout布局管理器能够使得多个组件共享同一显示空间,这些组件之间的关系像一叠重叠的扑克牌,只有最上面的组件是可见的。注意:在一个显示空间(卡片)中只能显示一个组件,因此,可使用容器嵌套的方法来显示多个组件。v 例9.4运行的结果如下图所示。v CardLayout类的构造方法如下: CardLayout()CardLayout()创建间距为零的对象。创建间距为零的对象。 CardLayout(int hgap, int vgap)CardLayout(int hgap, int vgap)创建带有水平创建带有水平hgaphgap和垂直和垂直vgapvgap间距的对象。间距的对象。v 为了使用叠在下面的组件,可以为每个组件取一名字,名字在用add()方法向容器添加组件时指定,需要某个组件时通过show()方法指定该组件的名字来选取它。也可以顺序使用这些组件,或直接指明选取第一个组件(用first()方法)或最后一个组件(用last()方法)。v 【例9.5】CardLayout布局。 import java.awt.import java.awt.* *; ; import javax.swing.import javax.swing.* *; ; public class CardLayoutDemo extends JAppletpublic class CardLayoutDemo extends JApplet CardLayout cl =new CardLayout(20,40); CardLayout cl =new CardLayout(20,40); / / 组件在卡片中有边界组件在卡片中有边界 JButton b1=new JButton( JButton b1=new JButton(卡片一卡片一);); JButton b2=new JButton( JButton b2=new JButton(卡片二卡片二);); JButton b3=new JButton( JButton b3=new JButton(卡片三卡片三);); public void init() public void init() getContentPane().setLayout(cl); getContentPane().setLayout(cl); getContentPane().add(card1,b1); getContentPane().add(card1,b1); getContentPane().add(card2,b2); getContentPane().add(card2,b2); getContentPane().add(card3,b3); getContentPane().add(card3,b3); v 程序运行结果如下图所示。程序中的三个按钮组件顺序添加到卡片布局管理器的各个卡片上,它们共享同一显示区域,因此只能见到最上面的“卡片一”按钮。v 5.GridBagLayoutv GridBagLayout是最复杂也最灵活的布局管理器。这个布局管理器将组件放入单元格中,但允许一些组件跨越单元格。v 可用GridBagLayout类的构造方法GridBagLayout()来创建一个GridBagLayout布局管理器。因GridBagLayout布局设置比较复杂,这里就不介绍了,请读者参看API说明或其他资料。 v 6.自定义布局v 若希望按照自己的要求来进行组件和界面图形元素的布局,可用容器的setLayout(null)方法将容器的布局管理器设置为空,然后用下面的方法设置组件在容器中的位置和大小: setBounds(int a,int b,int width,int height)setBounds(int a,int b,int width,int height)v 其中,参数a和b指定矩形形状的组件左上角在容器中的坐标,width和height指定组件的宽和高。v 【例9.6】设置自己的布局管理器。 import java.awt.import java.awt.* *; ; import javax.swing.import javax.swing.* *; ; class NullLayout extends JFrameclass NullLayout extends JFrame NullLayout() NullLayout() super( super(建设自己的布局管理器建设自己的布局管理器);); Container c=getContentPane(); Container c=getContentPane(); / / 也可不用内容窗格也可不用内容窗格 c.setLayout(null); c.setLayout(null); JButton jb1 =new JButton(按钮1); JButton jb2 =new JButton(按钮2); c.add(jb1);c.add(jb2); jb1.setBounds(10,10,100,30); jb2.setBounds(10,50,100,30); public static void main(String args) NullLayout nl=new NullLayout(); nl.setSize(200,150); nl.setVisible(true); v 程序的运行结果如下图所示。注意,采用这种方式的布局,组件的位置和大小将不随窗口大小的变化而变化。下图为例9.6的运行界面。9.3常用常用Swing组件组件v 9.3.1 容器组件v 1.JFrame框架v 框架,是JFrame类的对象,是swing GUI应用程序的主窗口。窗口有边界、标题、关闭按钮等。对Java应用程序,应至少包含一个框架,例9.1的应用程序即使用了框架。有时,小程序也使用框架。JFrame类继承于Frame类。JFrame类的构造方法如下: JFrame() JFrame() 创建无标题的初始不可见框架。创建无标题的初始不可见框架。 JFrame(String title) JFrame(String title) 创建标题为创建标题为titletitle的初始不可见框架。的初始不可见框架。 v 例如,创建带标题“Java GUI应用程序”的框架对象frame,可用语句: JFrame frame = new JFrame(Java GUIJFrame frame = new JFrame(Java GUI应用程序应用程序);v 要显示框架对象代表的框架窗口,可使用方法setVisible()。可用语句: frame.setVisible(true);frame.setVisible(true);v 可使得JFrame类对象frame表示的框架窗口显示到屏幕上。一般在显示框架前,可设置框架的初始显示大小可使用setSize()方法或pack()方法。例如: frame.setSize(200,150);frame.setSize(200,150); / / 设置框架窗口初始大小为设置框架窗口初始大小为200200 150150点点 frame.pack(); frame.pack(); / / 设置框架窗口初始大小为刚好只显示出所有的组件。设置框架窗口初始大小为刚好只显示出所有的组件。v 在向框架添加组件时,并不直接添加组件到框架,而是添加到内容窗格(content pane),改变其他特性(布局管理器、背景色等)也对内容窗格进行。要存取内容窗格,可通过getContentPane()方法, 若希望用自己的容器替换掉内容窗格(例如用JPanel),可以使用setContentPane()方法。 v 选择框架的关闭按钮后,框架窗口将自动关闭,但若是应用单个框架的应用程序,为了在选择框架的关闭按钮时能退出程序,应添加WindowListener监听器或书写下列代码: frame.setDefaultCloseOperation(frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); JFrame.EXIT_ON_CLOSE); v JFrame的缺省观感为Java (Metal), 若要使用其他的观感,必须显式设置。JFrame(应该说是内容窗格)的缺省布局管理器是BorderLayout。v 2. JPanel面板v JPanel是一种添加到其他容器使用的容器组件,可将组件添加到JPanel,然后再将JPanel添加到某个容器。JPanel也提供一个绘画区域,可代替AWT的画布Canvas (没有JCanvas)。v javax.swing.JPanel类继承于javax.swing.JComponent类,其构造方法有: public JPanel() public JPanel() 创建具有缺省创建具有缺省FlowLayoutFlowLayout布局的布局的JPanelJPanel对象。对象。 public JPanel(LayoutManager layout) public JPanel(LayoutManager layout) 创建具有指定布局管理创建具有指定布局管理器的器的JPanelJPanel对象。对象。v 将JPanel作为画布的绘画区域使用时,要使用下面的两个步骤:首先,设置画布绘图区域的大小;其次,使用paintComponent()方法(不是paint()方法)来绘图,在该方法体中,首先调用方法super.paintComponent()来清除显示区域。 v 例如: public void paintComponent(Graphics g) super.paintComponent(g); . v JPanel可指定边界,可用的边界有titled、etched、beveled 、line、matte、compound和empty等,也可以创建自己的边界。可用JComponent类的setBorder()方法设置边界。其用法如下: public void setBorder(Border border)v 其中,Border类的参数可用javax.swing.BorderFactory类中的方法获得。获取各种相应边界的方法为: createTitledBorder() createEtchedBorder() createBevelBorder() createRaisedBevelBorder() createLoweredBevelBorder() createLineBorder()createLoweredBevelBorder() createLineBorder() createMatteBorder() createCompoundBorder()createMatteBorder() createCompoundBorder() createEmptyBorder()createEmptyBorder()v 【例9.7】使用JPanel。 import java.awt.import java.awt.* *; ; import javax.swing.import javax.swing.* *; ; class JPanelDemo extends JPanel class JPanelDemo extends JPanel JButton b1 = new JButton(JPanel); JButton b1 = new JButton(JPanel); JButton b2 = new JButton(Demo); JButton b2 = new JButton(Demo); public JPanelDemo() public JPanelDemo() setBackground(Color.white); setBackground(Color.white); add(b1); add(b1); add(b2); add(b2); public static void main(String args) public static void main(String args) JPanel jp = new JPanelDemo(); JPanel jp = new JPanelDemo(); jp.setBorder( jp.setBorder( BorderFactory.createTitledBorder( BorderFactory.createTitledBorder( Hello,Border); Hello,Border); JFrame frame = new JFrame(JPanelDemo); JFrame frame = new JFrame(JPanelDemo); frame.setSize(200, 150); frame.setSize(200, 150); frame.setContentPane(jp); frame.setContentPane(jp); frame.setDefaultCloseOperation( frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE); JFrame.EXIT_ON_CLOSE); frame.setVisible(true); frame.setVisible(true); v例9.7程序运行结果如下图所示。v 3.JAppletv javax.swing.JApplet类是java.applet.Applet类的子类。使用Swing组件的小程序需继承JApplet类。v 除了所处的java包不同外,JApplet与Applet的主要区别还有:v (1)缺省的布局管理器不同v Applet缺省的布局管理器是FlowLayout,而JApplet(内容窗格)缺省的布局管理器是BorderLayout。v (2)加入组件的方式不同v Applet可直接加入组件,而JApplet缺省使用内容窗格ContentPane作为主容器。加入Swing组件时,要先使用JApplet的方法getContentPane()获得一个Container对象,再调用这个对象的add()方法将Swing组件加入到JApplet的容器中。v 4.JTabbedPanev javax. javax.swing.JTabbedPane类继承于javax.swing.JComponent,它的对象反映为一组带标签的面板,每个面板都可以存放组件,因此JTabbedPane是一容器组件。v JTabbedPane类的构造方法有: JTabbedPane()JTabbedPane()创建空对象,该对象具有缺省的标签位置创建空对象,该对象具有缺省的标签位置JTabbedPane.TOPJTabbedPane.TOP和缺省的布局策略和缺省的布局策略JTabbedPane.WRAP_TAB_LAYOUTJTabbedPane.WRAP_TAB_LAYOUT。 JTabbedPane(int tabPlacement)JTabbedPane(int tabPlacement)创建空对象,该对象具有指定创建空对象,该对象具有指定的标签位置:的标签位置:JTabbedPane.TOPJTabbedPane.TOP、JTabbedPane.BOTTOMJTabbedPane.BOTTOM、JTabbedPane.LEFTJTabbedPane.LEFT或或JTabbedPane.RIGHTJTabbedPane.RIGHT以及缺省的布局策略以及缺省的布局策略JTabbedPane.WRAP_TAB_LAYOUTJTabbedPane.WRAP_TAB_LAYOUT。 JTabbedPane(int tabPlacement, int tabLayoutPolicy)JTabbedPane(int tabPlacement, int tabLayoutPolicy)创建空创建空对象,该对象具有指定的标签位置和布局策略。对象,该对象具有指定的标签位置和布局策略。v【例9.8】使用JTabbedPane容器。 import java.awt.import java.awt.* *; ; import java