第5章图形用户界面设计 通过图形用户界面(graphics user interface,GUI),用户和程序之间可以方便地进行交互。本章主要介绍如何设计友好的图形用户界面应用程序。 5.1图形用户界面概述 1. awt和swing图形用户界面包 图形用户界面的构件一般包括菜单、输入输出组件、按钮、画板、窗口、对话框等,这些组件构成Java的抽象窗口工具包(Abstract Window Toolkit,AWT)。 Java语言提供了两种类型的图形用户界面包。在J2SE早期版本中,主要是awt图形用户界面包。它是一个强大的工具集,但隐藏着一个严重的问题: awt组件的设计是把与显示相关的工作和处理组件事件的工作都交给本地对等组件完成,因此用awt包编写的程序会在不同的操作平台上显示不同的效果。Java是遵循“一次编译,到处运行”理念的,而awt包中图形组件的绘制方法却不能做到这一点。 为了解决这个问题,Java在awt抽象窗口工具包的基础上,开发出了javax.swing图形用户界面包。javax.swing包内的组件称为swing组件。swing组件是用Java实现的轻量级(lightweight)组件,没有本地代码,不依赖操作系统的支持,这是它与awt组件的最大区别。由于awt组件通过与具体平台相关的对等类(peer)实现,因此swing比awt组件具有更强的实用性。swing在不同的平台上表现一致,并且有能力提供本地窗口系统不支持的其他特性。swing组件没有本地代码,不依赖操作平台,而且有更好的性能。swing组件的功能也有很大的增强,如增加了剪贴板、打印支持功能等。swing组件除了保持awt组件原有组件之外,还增加了一个丰富的高层组件集合,如表格(JTable)、树(JTree)。 把awt图形用户界面包称为awt组件,也称为重量组件; 把swing图形用户界面包称为swing组件,又称为轻量组件。 本章主要介绍swing组件的图形用户界面设计方法,但由于swing组件是awt的子类,不可避免地会涉及awt类包的有关内容。 2. swing组件的层次结构 swing组件的层次结构是为了编制基于事件的用户图形界面应用程序而在awt组件的基础上建立的。swing组件包括标准的图形用户界面的要素,如窗口、对话框、构件、事件处理、版面设计管理及接口、例外处理等。 swing组件的内容非常丰富,本章主要涉及JApplet、JFrame和JConponent三大类型。其中,JConponent是其他常用轻量级组件的父类。swing组件的层次结构如图51所示。 图51swing组件的层次结构 5.2窗体容器和组件 5.2.1窗体容器JFrame类 JFrame是带有标题、边框的顶层窗体。窗体是一个容器,在其内部可以添加其他组件。JFrame包含标题栏、菜单、可放置其他组件的窗体内部区域和自带的按钮。JFrame的外观如图52所示。 图52窗体的结构 1. 创建窗体 创建窗体有两种方法: 一种方法是创建JFrame类的子类,并重写其构造方法; 另一种方法是创建JFrame类的一个对象: JFrame win=new JFrame("最简单窗体"); 2. JFrame类的方法 JFrame类的常用方法如表51所示。 表51JFrame类的常用方法 方法名功能 JFrame();创建无标题的窗体 JFrame(String s);创建标题为s的窗体 setMenuBar(MenuBar mb);设置菜单 dispose();关闭窗体,释放占用资源 setVisible(bolean b);设置窗体的可见性 setSize(int width,int height);设置窗体的大小 Validate();使窗体中的组件能显示出来 续表 方法名功能 setTitle(String title);设置标题内容 getTitle();获取标题内容 setDefaultCloseOperation(int operation)设置窗体的关闭按钮可用,其中常数operation为EXIT_ON_CLOSE 下面分别举例说明通过构造JFrame对象设计窗体及利用JFrame子类设计窗体的方法。 【例51】通过构造JFrame对象创建最简单窗体。 1import javax.swing.*; 2class Example5_1 3{ 4public static void main(String[] args) 5{ 6JFrame win = new JFrame("最简单窗体");//实例化JFrame窗体对象 7win.setSize(300,200); //设置窗体大小 8win.setVisible(true); //设置窗体可见 9win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗体 10} 11} 图53最简单窗体 程序的运行结果如图53所示。 【程序说明】 程序的第9行setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)为设置窗体关闭按钮的关闭动作,如果没有该语句,当用户试图关闭窗口时,窗体只是隐藏,并没有真正从内存中退出。 【例52】通过构造JFrame子类创建最简单窗体。 1import javax.swing.*; 2classExample5_2 extends JFrame 3{ 4Example5_2()//构造方法 5{ 6setSize(300,200); //设置窗体大小 7setVisible(true); //设置窗体可见 8setTitle("最简单窗体");//设置窗体标题栏内容 9setDefaultCloseOperation(EXIT_ON_CLOSE);//设置关闭窗体,退出程序 10} 11public static void main(String[] args) 12{ 13Example5_2win = new Example5_2(); 14} 15} 程序的运行结果与例51相同,见图53。 5.2.2按钮和事件处理 1. 按钮JButton类 当单击应用程序中的按钮时,应用程序能触发某个事件从而执行相应的操作。在Java中,javax.swing包中的JButton类用于构建按钮对象。 (1) 按钮JButton类的常用方法。 JButton的常用方法如表52所示。 表52JButton的常用方法 方法名功能 JButton()创建不带标签文本或图标的按钮 JButton(Action a)创建一个按钮,其属性从Action中获取 JButton(Icon icon)创建一个带图标的按钮 JButton(String text)创建一个带标签文本的按钮 JButton(String text, Icon icon)创建一个带标签文本和图标的按钮 getLabel()获取按钮上的标签文本内容 setLabel(String label)设置按钮的标签文本内容 setText(Strings)设置按钮上的标签文本内容 setIcon(Iconicon)设置按钮上的图标 setHorizontalTextPosition(int textPosition)参数textPosition确定按钮上图标的位置,取值为SwingConstants .RIGHT、SwingConstants.LEFT、SwingConstants.CENTER、SwingConstants.LEADING、SwingConstants.TRAILING setVerticalTextPosition(int textPosition)参数textPosition确定按钮上图标的位置,取值为SwingConstants .CENTER、SwingConstants.TOP、SwingConstants.BOTTOM setMnemonic(charc)设置按钮的快捷键为(Alt+C) setEnabled(booleana)设置按钮可否单击 addActionListener(ActionListener l)设置事件源的监视器 removeActionListener(ActionListener l)删除事件监视器 (2) 创建按钮对象。 创建按钮对象的方法为: JButton btn = new JButton(String text); 由于按钮是一个普通组件,设计时必须放置到一个容器中。下面的示例就是将按钮放置到一个窗体容器内。 【例53】构造一个带按钮的窗体。 1/* 构造带按钮的窗体程序 */ 2import javax.swing.*; 3import java.awt. FlowLayout;//引用awt包的界面布局管理 4class Btn extends JFrame 5{ 6JButton btn = new JButton("确定"); //创建按钮对象 7Btn() 8{ 9setSize(300,200); //设置窗体大小 10setVisible(true); //设置窗体可见 11setDefaultCloseOperation(EXIT_ON_CLOSE);//设置关闭窗体,退出程序 12setLayout(new FlowLayout());//设置窗体为浮动布局 13add(btn);//把按钮对象添加到窗体中 14validate();//使窗体中的组件为可见 15} 16} 17 18public classExample5_3 19{ 20public static void main(String[] args) 21{ 22Btn btn = new Btn(); 23} 24} 【程序说明】 (1) 在本例设计Btn和Ex5_3两个类。按Java的命名规则,在一个文件中,只能有一个类可以用public修饰,且文件名必须和带public的类同名。因此,本程序的文件名必须命名为Example5_3.java。 (2) 程序的第3行为引用界面布局管理,第12行为把窗体布局设置为浮动布局。在窗体中如果不进行界面布局管理,添加到窗体中的按钮组 图54按钮程序运行结果 件将与窗体的内部空间一样大小。关于界面布局管理内容将在5.3节详细讲解。 (3) 第6行为实例化JButton按钮对象,第13行把实例化后的按钮对象添加到窗体中。 (4) 第14行validate()是窗体JFrame的一个方法,其功能是使窗体中的组件为可见。 程序运行结果如图54所示。 2. 处理按钮事件 用鼠标单击例53中的按钮什么也不会发生,这是因为在例53中没有定义按钮的事件。要定义按钮的处理事件,需要用到ActionListener接口。ActionListener是java.awt.event包中的一个接口,定义了事件的处理方法。java.awt.event包对这个接口的定义是: public interface ActionListener extends EventListener {//说明抽象方法 public abstract void actionPerformed(ActionEvent e) } 在设计按钮对象btn处理事件的类时,就要实现这个接口,其一般形式如下: classClassNameimplements ActionListener {  btn.addActionListener(this);  public void actionPerformed(ActionEvent e) {  } } 其中,ClassName为监听对象的类名,通过实现ActionListener接口,使得监视器能知道事件的发生。在Java中,要求产生事件的组件向它的监视器注册,这样事件源与监视器就建立了一个关联。建立关联的语句如下。 对象名.addActionListener(ClassName); 其中,对象是事件源,ClassName是监视器。例如: btn.addActionListener(this); 这条语句的意思是,按钮对象(事件源)btn向它的监视器(当前类)注册,也就是产生事件的事件源对象向监视器注册。 当单击按钮对象btn时,按钮对象(事件源)会产生一个ActionEvent事件,事件监视器监听到这个事件,把它作为实现ActionListener接口的actionPerformed方法参数,在actionPerformed方法中处理动作事件。 【例54】设计一个按钮事件程序。 1/* 按钮触发事件示例*/ 2import javax.swing.*; 3import java.awt.FlowLayout; 4import java.awt.event.*; 5class BtnIcon extends JFrame implements ActionListener 6{ 7ImageIcon icon = new ImageIcon("win.jpg");//创建图标对象 8JButton jbtn = new JButton("打开新窗体",icon); 9BtnIcon() 10{ 11setSize(200,200); 12setVisible(true); 13setTitle("按钮功能演示"); 14setDefaultCloseOperation(EXIT_ON_CLOSE); 15setLayout(new FlowLayout()); 16add(jbtn); 17validate(); 18jbtn.addActionListener(this); 19} 20public void actionPerformed(ActionEvent e) 21{ 22JFrame newf = new JFrame("新建窗体"); 23newf.setSize(150,150); 24newf.setVisible(true); 25} 26}//BtnIcon类结束 27public class Example5_4 28{ 29public static void main(String[] args) 30{new BtnIcon();} 31} 【程序说明】 (1) 在程序的第5行的类声明中,通过implements ActionListener实现监听接口。由于接口ActionListener在java.awt.event包中,故在第4行引用该包。 (2) 在程序的第18行设置监听对象(按钮Jbtn)向监听器(当前类)注册。一旦单击按钮,立刻被监听器接收,从而触发第20行actionPerformed()方法中的ActionEvent事件。 (3) 为了创建一个图标,可以用ImageIcon类创建图标对象: ImageIcon icon = new ImageIcon(String filename); 程序的第7行创建了一个图标对象,以便在按钮中使用。其中,filename为图标的路径及文件名,若缺省路径,则要将图标文件存放到程序的同一目录中。 程序运行结果如图55所示。 图55按钮事件 5.3面板容器和界面布局管理 5.3.1面板JPanel类 面板JPanel是一个可放置其他组件的容器。作为普通容器,必须将它放置到一个顶层容器(窗体)内。可以在JPanel中使用add方法放置其他组件。面板主要用于合理安排界面布局。 创建面板的一般步骤如下。 (1) 创建面板对象。 JPanel myPanel=new Panel(); (2) 将面板添加到窗体容器中。 add(myPanel); (3) 把组件放置到面板上。 myPanel.add(其他组件); 【例55】面板使用示例。 1/* 面板JPanel简单示例 */ 2import java.awt.*; 3import javax.swing.*; 4class PanelTest extends JFrame 5{ 6JPanel panel1=new JPanel(); 7JPanel panel2=new JPanel(); 8JButton button1=new JButton("Button1"); 9JButton button2=new JButton("Button2"); 10JButton button3=new JButton("Button3"); 11JButton button4=new JButton("Button4"); 12PanelTest() 13{ 14setSize(200,150); 15setVisible(true); 16setTitle("面板容器示例"); 17setDefaultCloseOperation(EXIT_ON_CLOSE); 18setLayout(new FlowLayout()); 19//将面板容器加入窗体中 20add(panel1); 21add(panel2); 22//将其他组件加入面板容器中 23panel1.add(button1); 24panel1.add(button2); 25panel2.add(button3); 26panel2.add(button4); 27panel1.setBackground(Color.red); 28panel2.setBackground(Color.cyan); 29validate(); 图56面板容器 30} 31} 32 33public class Example5_5 34{ 35public static void main(String[] args) 36{new PanelTest();} 37} 程序运行结果如图56所示。 5.3.2界面布局策略 当运行前面的例58程序时,如果把窗体拉大一些,窗体内部的组件也会跟着发生变化。那么,通过学习界面布局管理的知识以控制组件在容器的位置。 Java在java.awt包中定义了5种界面布局策略,分别是FlowLayout、BorderLayout、CardLayout、GridLayout和GridBagLayout。 设置布局的格式为: 容器对象.setLayout(布局策略); 1. 浮动布局FlowLayout 浮动布局是按照组件的顺序,用add方法将组件从左至右在一行排列,一行放不下时就自动换行,每行组件均按居中方式进行排列。这个布局方式在前面的示例中多次使用。 其设置的方法为: setLayout(new FlowLayout()); 2. 边界布局BorderLayout BorderLayout类把容器划分成5个区域,分别标记为North、South、West、East和Center。每个组件用add方法放置到区域中,中间区域的空间最大。 其设置的方法为: setLayout(new BorderLayout()); 【例56】边界布局示例。 1/* 边界布局示例 */ 2import java.awt.*; 3import javax.swing.*; 4class BordTest extends JFrame 5{ 6BordTest() 7{ 8setSize(300,200); 9setVisible(true); 10setTitle("边界布局示例"); 11setDefaultCloseOperation(EXIT_ON_CLOSE); 12setLayout(new BorderLayout()); 13//将其他组件加入到窗体 14add("East",new JButton("东")); 15add("South",new JButton("南")); 16add("West",new JButton("西")); 17add("North",new JButton("北")); 18add("Center", new JButton("中")); 图57边界布局排列组件 19validate(); 20} 21} 22 23public class Example5_6 24{ 25public static void main(String[] args) 26{new BordTest();} 27} 程序运行结果如图57所示。 3. 网格布局GridLayout GridLayout类以矩形网格形式对容器中的组件进行布局。容器被分成大小相等的单元格,单元格的大小由最大的构件决定,用add方法将组件一行一行地从左至右放置到布局的每个单元格中。 其设置的方法为: setLayout(new GridLayout(int row, int cols)); 其中,row是网格的行数; cols是网格的列数。 【例57】网格布局示例。 1/* 网格布局示例 */ 2import java.awt.*; 3import javax.swing.*; 4class GridTest extends JFrame 5{ 6GridTest() 7{ 8setSize(300,200); 9setVisible(true); 10setTitle("网格布局示例"); 11setDefaultCloseOperation(EXIT_ON_CLOSE); 12setLayout(new GridLayout(3,2));//设置网格布局 13//下面通过循环构造一组按钮并将其加入窗体中 14for (int i=1;i<=6 ;i++ ) 15{ 16add(new JButton("按钮"+i)); 17} 18validate(); 19} 20} 21 22public class Example5_7 23{ 24public static void main(String[] args) 25{ 26new GridTest(); 27} 28} 程序运行结果如图58所示。 4. 卡片布局CardLayout 这种布局包含几个卡片,在某一时刻只有一个卡片是可见的,而且第一个卡片显示的内容可用自己的布局来管理。 CardLayout的布局可以包含多个组件,但是实际上某一时刻容器只能从这些组件中选出一个来显示,就像一叠“扑克牌”每次只能显示最上面的一张,如图59所示。 图58网格布局排列组件 图59一叠“扑克牌” 卡片布局设置的方法为: setLayout(new CardLayout()); 卡片的顺序由组件对象本身在容器内部的顺序决定。CardLayout定义了一组方法,这些方法允许应用程序按顺序地浏览这些卡片,或显示指定的卡片。 CardLayout的主要方法如下。  first(Container parent): 显示容器parent中的第一张卡片。  next(Container parent): 显示容器parent中的下一张卡片。  previous(Container parent): 显示容器parent中的前一张卡片。  last(Container parent): 显示容器parent中的最后一张卡片。 【例58】卡片布局示例。 1/* 卡片布局示例 */ 2import java.awt.*; 3import java.awt.event.*; 4import javax.swing.*; 5class CardTest extends JFrame implements ActionListener 6{ 7JButton btn[] = new JButton[5]; 8CardLayout card=new CardLayout(); 9Panel p=new Panel(); 10CardTest() 11{ 12setSize(300,200); 13setVisible(true); 14setTitle("卡片布局示例"); 15setDefaultCloseOperation(EXIT_ON_CLOSE); 16add(p); 17p.setLayout(card); 18for (int i=1;i<=4;i++ ) 19{ 20btn[i]=new JButton("卡片"+i); 21p.add(btn[i],"卡片标识"+i); 22btn[i].addActionListener(this); 23} 24validate(); 25} 26 27public void actionPerformed(ActionEvent e) 28{ 29card.next(p); 30} 图510卡片布局显示最上面一个组件 31} 32 33public class Example5_8 34{ 35public static void main(String[] args) 36{ 37new CardTest(); 38} 39} 程序运行结果如图510所示。 5.4JComponent类组件的使用 5.4.1JComponent类组件 JComponent类是除顶层容器外的所有swing组件的父类,其常用子类如表53所示。 表53JComponent类的一些常用子类 类名功能类名功能 JButton创建按钮对象 JComboBox创建下拉列表对象 JCheckBox创建复选框对象 JFileChooser创建文件选择器 JLabel创建文本标签 JMenu创建菜单对象 JMenuBar创建菜单条对象 JMenuItem创建菜单项对象 JPanel创建面板对象 JPasswordField创建口令文本框对象 JPopupMenu创建弹出式菜单 JProgressBar创建进度指示条 JRadioButton创建单选按钮 JScrollBar创建滚动条 JScrollPane创建滚动窗体 JSlider创建滑杆 JSplitPane创建拆分窗体 JTable创建表格 JTestArea创建文本区 JToolBar创建工具条 JToolTip创建工具提示对象 JTree创建树对象 JComponent类的常用方法如表54所示,它们是表53中所列的子类都继承了这些方法。 表54JComponent类的常用方法 类别方法名功能 设置组件的颜色 voidsetBackground(Color c)设置组件的背景色 voidsetForeground(Color c)设置组件的前景色 设置组件的字体 void setFont(Font f)设置组件上的字体 Font(String name, int style, int size)字体的构造方法: name为字体名称,style为字体式样size为字体大小 设置组件的大小与位置 void setSize(int width, int height)设置组件的宽度和高度 void setLocation(int x, int y)设置组件在容器中的位置,左上角坐标为(0,0) void setBounds(int x, int y, int width, int height)设置组件在容器中的位置及组件大小 设置组件的激活与可见性 void setEnabled(boolean b)设置组件是否被激活 boolean isEnabled()判断组件是否为激活状态 void setVisible(boolean b)设置组件是否可见 在上述设置组件颜色的方法中,Color类是Java.awt包中的类。用Color类的构造方法Color(int red,int green,int blue)可以创建一个颜色对象,三个颜色值取值都为0~255。Color类还有red、blue、green、orange、cyan、yellow、pink等静态常量。 5.4.2文本组件和标签 1. JTextComponent类 图511JTextComponent类组件 的继承关系 JTextComponent是一个允许设置、检索和修改文本的类。它是swing文本组件的基类,通过它定义了JTextField、JTextArea和JEditorPane 3个子类。它们的继承关系如图511所示。 JTextComponent类的常用方法如表55所示。 表55JTextComponent类常用方法 方法名功能 void setText(String t)设置文本内容 string getText()获取文本内容 boolean isEdit()检测文本的可编辑性 void setEditable(boolean b)设置文本的可编辑性 string getSelectedText()获取选取文本内容 void select(int selStart,int selEnd)选取文本内容 void copy()将选定的内容传输到系统剪贴板 void cut()将选定的内容传输到系统剪贴板,并把文本组件中的内容删除 由于JTextComponent是文本框JTextField类、文本区JTextArea类及文本组件JEditorPane共同的父类。因此,下面要介绍的文本框JTextField类、文本区JTextArea类及文本组件JEditorPane都继承了JTextComponent的方法属性。 2. 文本框JTextField 文本框JTextField是对单行文本进行编辑的组件,用来接受用户的输入码或显示可编辑的文本。 (1) 文本框JTextField类的定义。 swing对文本框JTextField类的定义如下。 1public class JTextField extends JTextComponent 2{ 3public JTextField(); 4publicJTextField(String text); 5public JTextField(int columns); 6publicJTextField(String text,int columns); 7public void addActionListener(ActionListener l); 8public void remove ActionListener(ActionListener l); 9} 其中, 第3~6行是文本框的构造方法。 第7行addActionListener(ActionListener l)为指定事件监听者。 第8行remove ActionListener(ActionListener l)为删除事件监听者。 由于JTextField是JTextComponent的子类,因此还具有JTextComponent所有的方法和属性。 (2) 创建文本框。 创建文本框时,一般要以初始的文本字符串或能容纳的字符数为参数: JTextFieldtext = newJTextField(String str); (3) 主要方法。 它主要继承其父类JTextComponent的方法。从上述文本框的定义可知,它可以实现ActionListener监听接口的方法。 【例59】文本框应用示例。 1/* JTextField 类示例 */ 2import javax.swing.*; 3import java.awt.FlowLayout; 4class TxtfdTest extends JFrame 5{ 6JTextField txt;//声明文本框对象 7TxtfdTest() 8{ 9setSize(300,200); 10setVisible(true); 11setTitle("创建文本框示例"); 12setDefaultCloseOperation(EXIT_ON_CLOSE); 13setLayout(new FlowLayout());//设置窗体为浮动布局 14txt=new JTextField(20);//对象实例化 15add(txt);//将文本框添加到窗体中 16validate(); 17txt.setText("重新设置了文本"); //设置文本内容 18} 19} 20 21public class Example5_9 22{ 23public static void main(String[] args) 24{ 25new TxtfdTest(); 26} 27} 【程序说明】 图512文本框组件程序运行结果 程序的第2行引用了swing类包,因此可以在第4行将类声明为JFrame的子类,并且可以使用文本组件JTextField。第6行声明TextField对象,第14行实例化对象。第15行把文本框添加到窗体中,第16行的validate方法使文本框对象显示出来。第17行重新设置文本框的内容。 程序运行结果如图512所示。 3. 密码框JPasswordField 密码框JPasswordField是JtextField的子类,允许编辑单行文本,可以设置为不显示输入的原始字符,而是显示指定的回显字符。 JPasswordField类的主要方法为setEchoChar(char c),其中的字符c为回显字符。 【例510】设计一个密码验证程序。 1/* 密码框示例*/ 2import javax.swing.*; 3import java.awt.*; 4import java.awt.event.*; 5class Passwd extends JFrame implements ActionListener 6{ 7JLabel lb=new JLabel("请输入密码:");//创建标签对象 8JPasswordField txt1=newJPasswordField(25); //创建密码框对象 9JButton bn=new JButton("确定"); 10JTextField txt2=new JTextField(25); 11Passwd() 12{ 13setSize(300,200); 14setVisible(true); 15setTitle("密码验证"); 16setDefaultCloseOperation(EXIT_ON_CLOSE); 17setLayout(new FlowLayout()); 18add(lb); 19add(txt1); 20txt1.setEchoChar('*');//设置回显的字符为*号 21add(bn); 22add(txt2); 23validate(); 24bn.addActionListener(this); 25} 26 27public void actionPerformed(ActionEvent e) 28{ 29if (txt1.getText().equals("abc"))//比较字符串相等 30txt2.setText("密码正确!!"); 31else 32txt2.setText("密码错误!!"); 33} 34} 35 36public classExample5_10 37{ 38public static void main(String[] args) 39{ 40new Passwd(); 41} 42} 图513密码框组件程序运行结果 【程序说明】 程序的第29行,比较两个字符串的内容是否相等,要用equals方法。若比较两个数值是否相等,则用==符号。 程序运行结果如图513所示。 4. 文本区JTextArea 文本区JTextArea是对多行文本进行编辑的组件,用控制符来控制文本的格式。例如,\n为换行,\t为插入一个Tab字符。 (1) 文本区JTextArea类的定义。 TextArea类是JTextComponent的子类,继承了其父类的方法和属性。swing对这个类的定义如下。 1public class JTextArea extends JTextComponet 2{ 3public JTextArea() 4public JTextArea(String text) 5public JTextArea(int rows,int columns) 6public JTextArea(String text,int rows,int cols) 7public void append(String str) 8public void insert(String str,int pos) 9public void replaceRange(String str,int start,int end) 10} 其中, 第3~6行是文本区的构造方法。 第7行append(String str)方法向文本区追加文本内容。 第8行insert(String str,int pos)方法在指定的位置插入文本内容。 第9行replaceRange(String str,int start,int end)方法替换指定的开始与结束位置间的文本内容,str为替换的文本,start为开始位置,end为结束位置。 (2) 创建文本区。 通常创建文本区时,要说明这个文本区的行数、列数或文本内容: JTextArea txt1 = new JTextArea(7,35); (3) 主要方法。 它主要继承JTextComponent类的方法,从文本区的定义可知,它还有append(String str)等方法。 通过下面的例子,可以了解文本组件的基本功能及使用方法。 【例511】JTextArea类示例。 1/* JTextArea 类示例 */ 2import javax.swing.*; 3import java.awt.*; 4import java.awt.event.*; 5class AreaTest extends JFrame implements ActionListener 6{ 7JTextArea txt1 = new JTextArea(7,35); //创建文本区对象 8JTextField txt2 = new JTextField(35); //创建文本框对象 9String str = "窗外飘起蒙蒙小雨,\n平添一夜寒意,"+ 10"\n多少的思绪藏在心底,"; 11AreaTest() 12{ 13setSize(400,300); 14setVisible(true); 15setTitle("文本组件示例"); 16setDefaultCloseOperation(EXIT_ON_CLOSE); 17setLayout(new FlowLayout());//设置浮动布局 18txt1.setText(str);//设置文本区的文本内容 19add(txt1); //将文本区添加到窗体中 20add(txt2);//将文本框添加到窗体中 21validate(); 22txt2.addActionListener(this);//把文本框注册为监听对象 23} 24 25public void actionPerformed(ActionEvent e) 26{ 27String s = txt2.getText(); //从文本框中获取文字内容 28txt1.append("\n"+s); //将文本框的字符串追加到文本区中 29} 30} 31 32public classExample5_11 图514文本区组件程序运行结果 33{ 34public static void main(String[] args) 35{new AreaTest();} 36} 程序运行结果如图514所示,在文本框中输入文字内容,按Enter键,则将文本框中的文字追加到文本区中。 5. 标签JLabel类 标签是用户只能查看其内容但不能修改的文本组件,一般用作说明。在例510密码验证程序中已经使用了标签。标签JLabel上可以添加图像,当鼠标指针悬停在标签上时,可以显示一段提示文字。标签JLabel的常用方法如表56所示。 表56标签JLabel类常用方法 方法名功能 JLabel()创建空标签的构造方法 JLabel(String text)创建具有文字text的构造方法 JLabel(Icon icon)创建具有图标icon的构造方法 JLabel(String s, Icon icon,int textPosition)创建具有文字、图标和排列方式的构造方法 参数textPosition确定标签上图标的位置,取值为SwingConstants.RIGHT、SwingConstants.LEFT、SwingConstants.CENTER、SwingConstants.LEADING、SwingConstants.TRAILING setText(String s)设置标签内容 setIcon(Icon icon)设置标签的图标 setToolTipText(String text)设置当鼠标指针悬停在标签上时显示文字text内容 【例512】创建一个包含带有图标的按钮和标签的窗体。 1/* 带有图标的按钮和标签 */ 2import javax.swing.*; 3import java.awt.*; 4import java.awt.event.*; 5class LbTest extends JFrame implements ActionListener 6{ 7LbTest(String s) 8{ 9setSize(300,200); 10setVisible(true); 11setTitle(s); 12setLayout(new FlowLayout()); 13ImageIcon icon1=new ImageIcon("s1.jpg"); 14ImageIcon icon2=new ImageIcon("s2.jpg"); 15ImageIcon icon3=new ImageIcon("s3.jpg"); 16JButton jbtn=new JButton("我是按钮",icon1); 17jbtn.setRolloverIcon(icon2); //当鼠标指针悬停在按钮上时变换图标 18JLabel jlb=new JLabel("我是标签",icon3,SwingConstants.CENTER); 19jlb.setToolTipText("QQ头像");//当鼠标指针悬停在标签上时显示提示文本 20add(jbtn); 21add(jlb); 22jbtn.addActionListener(this); 23setDefaultCloseOperation(EXIT_ON_CLOSE); 24validate(); 25} 26public void actionPerformed(ActionEvent e) 27 { 28JInternalFrame in_window;//声明内部窗体对象 29in_window=new JInternalFrame("内部窗体",true,true,true,true); 30in_window.setSize(250,200); 31in_window.setVisible(true); 32add(in_window); 33JTextArea text=new JTextArea(5,15);//创建文本区对象 34in_window.add(text,BorderLayout.CENTER);//按边界布局添加到窗体中 35} 36} 37 38public class Example5_12 39{ 40public static void main(String args[]) 41{ 42LbTest win=new LbTest("有图标的按钮和标签"); 43} 44} 【程序说明】 (1) 程序的第16行和第18行创建了一个带图标的按钮和一个带图标的标签。 (2) 第17行设置按钮对象的翻滚图标,即当鼠标指针悬停在按钮上时,按钮上的图标由icon1变换为icon2。 (3) 第19行设置标签的提示文本,当鼠标指针悬停在标签上时将显示提示文本内容。 (4) 在第28行和第29行创建了一个内部窗体对象。JinternalFrame的构造方法为: JInternalFrame(String title,可否改变大小,可否关闭,可否最大化,可否最小化) 当参数为true时,可改变; 否则,不可改变。 程序运行结果如图515所示。 图515带有图标的按钮和标签 5.4.3单选按钮、复选框和下拉列表 单选按钮(JRadioButton)、复选框(JCheckBox)和下拉列表(JComboBox)是一组表示多种“选择”的swing组件。 1. 单选按钮(JRadioButton)和复选框(JCheckBox) 单选按钮JradioButton和复选框JCheckBox都只有两种状态: 选中或未选中。它们的构造方法和其他常用方法类似,故把它们放在一起介绍。 复选框JCheckBox的常用方法如表57所示。 表57复选框JCheckBox及单选按钮JradioButton类常用方法 方法名功能 JCheckBox()或JRadioButton()没有标签的构造方法 JCheckBox(String s)或JRadioButton(String s)具有标签s的构造方法 JCheckBox(Icon icon)或JRadioButton(Icon icon)具有图标icon的构造方法 JCheckBox(String s, Icon icon)或 JRadioButton(String s, Icon icon)具有标签和图标的构造方法 JCheckBox(String s, Icon icon,boolean t)或 JRadioButton(String s, Icon icon,boolean t)具有标签和图标且初始状态为t的构造方法 getItem()获取产生事件的对象 getStateChange()返回该选择项是否被选中 【例513】创建包含单选按钮和复选框的窗体。 1/* 单选按钮和复选框示例 */ 2import java.awt.*; 3import java.awt.event.*; 4import javax.swing.*; 5class BRTest extends JFrame implements ItemListener,ActionListener 6{ 7JTextField text = new JTextField(15); ; 8BRTest(String s) 9{ 10setSize(200,200); 11setVisible(true); 12setTitle(s); 13setLayout(new FlowLayout()); 14//添加3个复选框 15JCheckBox cb1 = new JCheckBox("C语言"); 16cb1.addItemListener(this); 17add(cb1); 18JCheckBox cb2 = new JCheckBox("C++语言"); 19cb2.addItemListener(this); 20add(cb2); 21JCheckBox cb3 = new JCheckBox("Java语言"); 22cb3.addItemListener(this); 23add(cb3); 24//添加3个单选按钮 25JRadioButton b1 = new JRadioButton("鲜花"); 26b1.addActionListener(this); 27add(b1); 28JRadioButton b2 = new JRadioButton("鼓掌"); 29b2.addActionListener(this); 30add(b2); 31JRadioButton b3 = new JRadioButton("鸡蛋"); 32b3.addActionListener(this); 33add(b3); 34//定义按钮组,单选按钮只有放到按钮组中才能实现单选功能 35ButtonGroup bg = new ButtonGroup(); 36bg.add(b1); 37bg.add(b2); 38bg.add(b3); 39//添加文本框 40add(text); 41validate(); 42setDefaultCloseOperation(EXIT_ON_CLOSE); 43} 44public void itemStateChanged(ItemEvent ie) 45{ 46JCheckBox cb = (JCheckBox)ie.getItem(); 47text.setText(cb.getText()); 48} 49public void actionPerformed(ActionEvent ae) 50{ 51text.setText(ae.getActionCommand()); 52} 53} 54//主类 55public class Example5_13 56{ 57public static void main(String args[]) 58{ 59new BRTest("单选按钮和复选框示例"); 60} 61} 【程序说明】 (1) 复选框JCheckBox实现ItemListener接口,通过itemStateChanged方法,触发ItemEvent事件,如本程序的第44~48行。 图516单选按钮和复选框示例 (2) 单选按钮JRadioButton实现ActionListener接口,通过actionPerformed方法,触发ActionEvent事件,如本程序的第49~52行。 (3) 程序的第35~38行将单选按钮JRadioButton对象放到按钮组ButtonGroup中,只有放到按钮组中才能实现一次只能选中一个按钮的单选功能。 程序运行结果如图516所示。 2. 下拉列表(JComboBox) 下拉列表(JComboBox)通常显示一个可选条目,允许用户在一个下拉列表中选择不同条目,用户也可以在文本区内输入选择项。JComboBox的构造函数如下: JComboBox() JComboBox(Vector v) 其中,v是初始选项。 要增加选项,则使用方法: void addItem(Object obj) 其中,obj是加入下拉列表的对象。 【例514】创建包括一个下拉列表和一个标签的窗体。标签显示一个图标。下拉列表的可选条目是“中国”“俄罗斯”“韩国”“联合国”。当选择一个图标,标签就更新为这个国家的国旗。 1/* 下拉列表示例 */ 2import java.awt.*; 3import java.awt.event.*; 4import javax.swing.*; 5class CobTest extends JFrame implements ItemListener 6{ 7JLabel jlb; 8ImageIcon france, germany, italy, japan; 9CobTest(String s) 10{ 11setSize(300,200); 12setVisible(true); 13setTitle(s); 14setDefaultCloseOperation(EXIT_ON_CLOSE); 15setLayout(new FlowLayout()); 16JComboBox jc = new JComboBox(); 17jc.addItem("中国"); 18jc.addItem("俄罗斯"); 19jc.addItem("韩国"); 20jc.addItem("联合国"); 21jc.addItemListener(this); 22add(jc); 23jlb = new JLabel(new ImageIcon("中国.jpg")); 24add(jlb); 25validate(); 26} 27public void itemStateChanged(ItemEvent ie) 28{ 29String s = (String)ie.getItem().toString(); 图517下拉列表程序运行结果 30jlb.setIcon(new ImageIcon(s + ".jpg")); 31} 32} 33//主类 34public class Example5_14 35 { 36public static void main(String args[]) 37{new CobTest("下拉列表示例");} 38 } 程序运行结果如图517所示。 5.4.4卡片选项页面(JTabbedPane) 在5.3.2节中介绍过卡片布局CardLayout,该布局不太直观,swing用JTabbedPane类对它进行了修补,由JTabbedPane处理这些卡片面板。在设计用户操作界面时,使用卡片选项页面,可以扩大安排功能组件的范围,用户操作起来更加方便。 【例515】卡片选项页面示例。 1/* 卡片选项页面 */ 2import javax.swing.*; 3import java.awt.*; 4import java.awt.event.*; 5class TtpDemo extends JFrame 6{ 7TtpDemo() 8{ 9super("卡片选项页面示例"); 10setSize(300,200);setVisible(true); 11JTabbedPane jtp = new JTabbedPane(); 12ImageIcon icon1 = new ImageIcon("c1.gif"); 13ImageIcon icon2 = new ImageIcon("c2.gif"); 14ImageIcon icon3 = new ImageIcon("c3.gif"); 15jtp.addTab("城市",icon1, new CitiesPanel(),"城市名称"); 16jtp.addTab("文学", icon2, new BookPanel(),"文学书目"); 17jtp.addTab("网站", icon3, new NetPanel(),"精选网址"); 18getContentPane().add(jtp); 19validate(); 20setDefaultCloseOperation(EXIT_ON_CLOSE); 21} 22} 23//定义面板CitiesPanel 24class CitiesPanel extends JPanel 25{ 26CitiesPanel() 27{ 28JButton b1 = new JButton("北京"); 29JButton b2 = new JButton("上海"); 30JButton b3 = new JButton("深圳"); 31JButton b4 = new JButton("厦门"); 32add(b1); add(b2); add(b3); add(b4); 33} 34} 35//定义面板BookPanel 36class BookPanel extends JPanel 37{ 38BookPanel() 39{ 40JCheckBox cb1 = new JCheckBox("西游记"); 41JCheckBox cb2 = new JCheckBox("三国演义"); 42JCheckBox cb3 = new JCheckBox("红楼梦"); 43add(cb1); add(cb2); add(cb3); 44} 45} 46//定义面板NetPanel 47classNetPanel extends JPanel 48{ 49NetPanel() 50{ 51JComboBox jcb = new JComboBox(); 52jcb.addItem("思维论坛"); 53jcb.addItem("百度搜索"); 54jcb.addItem("Java爱好者"); 55add(jcb); 56} 57} 58//主类 59public class Example5_15 60{public static void main(String args[]) 61{new TtpDemo();} 62} 【程序说明】 (1) 在程序的第23~57行,设计了三个面板类(CitiesPanel、BookPanel和NetPanel)。 (2) 在程序的第11行建立JTabbedPane的实例对象JTp。 (3) 通过实例对象JTp调用方法addTab()将面板添加到JTabbedPane中。 addTab方法有3种结构方式:  addTab(String title, Component component);  addTab(String title, Icon icon, Component component);  addTab(String title, Icon icon, Component component, String tip); 图518卡片选项页面 其中,title为卡片标题; icon为卡片图标; component为放到选项页面中的面板; tip为当鼠标停留在该页面标题时显示的提示文字。 本程序的第15~17行使用的是addTab方法的第三种结构方式。 程序运行结果如图518所示。 5.4.5滑杆(JSlider)和进度指示条(JProgressBar) 滑杆JSlider能通过一个滑块的来回移动输入数据,在很多情况下显得直观(如声音控制)。进程条JProgressBar从“空”到“满”显示相关数据的状态,因此用户得到了一个状态的透视。下面的例子将滑动块同进程条挂接起来,当移动滑动块时,进程条也相应地改变。 【例516】滑杆和进度指示条配合使用示例。 1/* 滑杆和进度指示条 */ 2Import java.awt.*; 3Import java.awt.event.*; 4Import javax.swing.*; 5Import javax.swing.event.*; 6Import javax.swing.border.*; 7class P extends JPanel { 8JProgressBar pb = new JProgressBar(); 9JSlider sb = new JSlider(JSlider.HORIZONTAL, 0, 100, 60); 10public P() { 11setLayout(new GridLayout(2,1)); 12add(pb); 13sb.setValue(0); 14sb.setPaintTicks(true); 15sb.setMajorTickSpacing(20); 16sb.setMinorTickSpacing(5); 17sb.setBorder(new TitledBorder("移动滑杆")); 18pb.setModel(sb.getModel()); 19pb.setStringPainted(true); 20add(sb); 21} 22} 23public class Example5_16{ 24public static void main(String args[]) { 25JFrame f=new JFrame("滑杆和进度指示条"); 26f.setSize(300,150); 27f.add(new P()); 28f.show(); 29f. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 30} 31} 【程序说明】 (1) 进程指示条JProgressBar是用颜色动态填充一个长条矩形的组件,通常用于显示某任务完成的进度情况。它有以下3种常用的构造方法。  JProgressBar(),  JProgressBar(int min, int max),  JProgressBar(int orient, int min, int max)。 其中,参数orient决定进度指示条是水平放置还是垂直放置,其取值为JProgressBar.HORIZONTAL或JProgressBar.VERTICAL; min和max表示进度指示条的最大值和最小值。 在程序的第8行,应用了第一种构造方法建立JProgressBar对象。它的最大值和最小值是系统默认的,分别取值100和0,即把进度指示条100等分。 本程序用到JProgressBar的方法如下。  setModel(BoundedRangeModel newModel): 进度条与任务源newModel挂接。  setStringPainted(boolean b): 是否允许在进度条中显示完成进度的百分比。 图519滑杆和进度指示条 程序的第18行,设置进度条的任务源为JSlider; 程序的第19行,设置允许在进度条中显示完成的百分比数。 (2) JSlider的构造方法与作用基本与JProgressBar类似,用于显示某任务完成的进度情况,不同之处是它可以用鼠标拖动。 程序运行结果如图519所示。 5.4.6表格(JTable) 表格(JTable)是在设计用户界面(user interface)时非常有用的一个组件; 尤其在需要将统计数据非常清楚且有条理地呈现在用户面前时,表格设计更能显出它的重要。JTable组件的主要功能是把数据以二维表格的形式显示出来。 表格JTable的常用方法如表58所示。 表58表格JTable常用方法 方法名功能 JTable()创建一个新的JTable,使用系统默认的Model JTable(int row, int col)创建具有row行、col列的空表格 JTable(object[][]rowData,object[]columnNames)创建显示二维数组数据表格,且可以显示列的名称。第一个参数是数据,第二个参数是在表格第一行中显示列的名称 JTable(TableModel dm)创建表格并设置数据模式 JTable(Vector[][]rowData,Vector[]columnNames);创建以Vector为输入来源的数据表格。第一个参数是数据,第二个参数是在表格第一行中显示列的名称 getModel()获取表格的数据来源对象 【例517】利用JTable编制员工档案表。 1/* 简单JTable表格 */ 2import javax.swing.*; 3import java.awt.*; 4import java.awt.event.*; 5class TableDemo extends JFrame 6{ 7public TableDemo() 8{ 9super("员工档案表"); 10String[] columnNames = {"姓名","职务","电话","月薪","婚否"}; 11Object[][] data = { 12{"李强","经理","059568790231",new Integer(5000),new Boolean(true)}, 13{"吴虹","秘书","059569785321",new Integer(3500),new Boolean(true)}, 14{"陈卫东","主管","059565498732",new Integer(4500),new Boolean(false)}, 15{"欧阳建","保安","059562796879",new Integer(2000),new Boolean(true)}, 16{"施乐乐","销售","059563541298",new Integer(4000),new Boolean(false)} 17}; 18JTable table = new JTable(data,columnNames); 19table.setPreferredScrollableViewportSize(new Dimension(500,70)); 20JScrollPane scrollPane = new JScrollPane(table); 21getContentPane().add(scrollPane, BorderLayout.CENTER); 22setDefaultCloseOperation(EXIT_ON_CLOSE); 23pack(); 24setVisible(true); 25} 26} 27//主类 28public class Example5_17 29{ 30public static void main(String[] args) 31{ 32TableDemo frame = new TableDemo(); 33} 34} 【程序说明】 (1) 程序第10行为表格的表头,即各列标题,存放到字符串数组columnNames中。 (2) 程序第11~17行定义二维数组data存放表格数据。 (3) 程序第18行创建一个JTable类对象,构成一个以数组columnNames为列标题、以数组data为内容的表格。 (4) 程序第19行定义表格的显示尺寸。 (5) 程序第20行创建一个带滚动条的面板,把表格放到面板中。 (6) 程序第21行将带滚动条的面板添加到窗体中。 程序运行结果如图520所示。 图520简单表格 通过上面的例子可知,利用JTable类创建一个表格很简单,只要用数组作为表格的数据输入,将数组的元素填入JTable中,一个基本的表格就产生了。不过,这种方法虽然简便,但创建的表格还有不少缺陷。例如,上例表格中的每个单元格都只能接受同一种类型的数据,数据类型皆显示为String类型,原来声明为Boolean的数据都以String类型的形式出现。为了对解决这种复杂的情况,swing提供了多种Model来解决这个问题,如TableModel类、AbstractTableModel类等。这些类均放在类库javax.swing.table package中,可以在Java API中找到这个package,下面通过改造上例来说明其用法。 设计表格程序时,依据MVC(ModelViewController)的设计思想,先创建一个AbstractTableModel类型的对象来存放和处理数据,由于这个类是从AbstractTableModel类中继承的,其中有几个方法需要覆盖重写,如getColumnCount、getRowCount、getColumnName和getValueAt。因为JTable会从这个对象中自动获取表格显示需要的数据,AbstractTableModel类的对象负责表格大小的确定(行、列)、内容的填写、赋值、表格单元更新检测等一切与表格内容有关的属性及其操作。JTable类生成的表格对象以该TableModel为参数,并负责将TableModel对象中的数据以表格的形式显示出来。 【例518】修改例517,编制一个加强的员工档案表格。 1/*JTable表格应用*/ 2import javax.swing.JTable; 3import javax.swing.table.AbstractTableModel; 4import javax.swing.JScrollPane; 5import javax.swing.JFrame; 6import javax.swing.SwingUtilities; 7import javax.swing.JOptionPane; 8import java.awt.*; 9import java.awt.event.*; 10class TableDemo extends JFrame 11{ 12public TableDemo() 13{ //首先调用父类JFrame的构造方法生成一个窗口 14super("员工档案表"); 15//myModel存放表格的数据 16MyTableModel myModel = new MyTableModel(); 17//表格对象table的数据来源是myModel对象 18JTable table = new JTable(myModel); 19//表格的显示尺寸 20table.setPreferredScrollableViewportSize(new Dimension(500,70)); 21//产生一个带滚动条的面板 22JScrollPane scrollPane = new JScrollPane(table); 23//将带滚动条的面板添加到窗口中 24getContentPane().add(scrollPane, BorderLayout.CENTER); 25setDefaultCloseOperation(EXIT_ON_CLOSE); 26} 27} 28//把要显示在表格中的数据存入字符串数组和Object数组中 29class MyTableModel extends AbstractTableModel 30{ 31private boolean DEBUG = true; 32//表格中第一行所要显示的内容存放在字符串数组columnNames中 33final String[] columnNames = {"姓名","职务","电话","月薪","婚否"}; 34//表格中各行的内容保存在二维数组data中 35final Object[][] data = { 36{"李强", "经理","059568790231",new Integer(5000), new Boolean(false)}, 37{"吴虹", "秘书","059569785321",new Integer(3500), new Boolean(true)}, 38{"陈卫东", "主管","059565498732",new Integer(4500), new Boolean(false)}, 39{"欧阳建", "保安","059562796879",new Integer(2000), new Boolean(true)}, 40{"施乐乐", "销售","059563541298",new Integer(4000), new Boolean(false)} 41}; 42/* 下面是重写AbstractTableModel中的方法,其主要用途是被JTable对象调用, 43* 以便在表格中正确地显示出来。 44* 要注意根据采用的数据类型加以恰当实现 45*/ 46//获得列的数目 47public int getColumnCount() 48{return columnNames.length;} 49//获得行的数目 50public int getRowCount() 51{return data.length;} 52//获得某列的名字,而目前各列的名字保存在字符串数组columnNames中 53public String getColumnName(int col) 54{return columnNames[col];} 55//获得某行某列的数据,而数据保存在对象数组data中 56public Object getValueAt(int row, int col) 57{return data[row][col];} 58//判断每个单元格的类型 59public Class getColumnClass(int c) 60{return getValueAt(0, c).getClass();} 61//将表格声明为可编辑的 62public boolean isCellEditable(int row, int col) 63{ 64if (col < 2) {return false;} 65else {return true;} 66} 67//改变某个数据的值 68public void setValueAt(Object value, int row, int col) 69{ 70if (DEBUG) 71{ 72System.out.println("Setting value at "+row+","+col 73+" to "+value+" (an instance of "+value.getClass()+")"); 74} 75if (data[0][col] instanceof Integer && !(value instanceof Integer)) 76{ 77try 78{ 79data[row][col] = new Integer(value.toString()); 80fireTableCellUpdated(row, col); 81} 82catch (NumberFormatException e) //捕获异常,当程序发生异常时触发 83{ 84TableDemo table=new TableDemo(); 85JOptionPane.showMessageDialog(table, 86"The \"" + getColumnName(col) 87+ "\" column accepts only integer values."); 88} 89} else { 90data[row][col] = value; 91fireTableCellUpdated(row, col); 92} 93if (DEBUG) 94{ 95System.out.println("New value of data:"); 96printDebugData(); 97} 98} 99private void printDebugData()//采用双重循环结构,输出二维数组元素 100{ 101int numRows = getRowCount(); 102int numCols = getColumnCount(); 103for (int i=0; i < numRows; i++) //外循环控制行 104{ 105System.out.print(" row " + i + ":"); 106for (int j=0; j < numCols; j++) //内循环控制列 107{System.out.print(" " + data[i][j]);} 108System.out.println(); 109} 110System.out.println("--------------------------"); 111} 112} 113//主类 114public class Example5_18 115{ 116public static void main(String args[]) 117{ 118TableDemo frame = new TableDemo(); 119frame.pack(); 120frame.setVisible(true); 121} 122} 程序运行结果如图521所示。 图521加强的表格 5.5菜单与对话框 5.5.1菜单 菜单是图形用户界面程序设计经常使用的组件。菜单又分为下拉式菜单(JMenu)和弹出式菜单(JPopupMenu)。 一个菜单由多个菜单项组成,选择一个菜单项就可以触发一个动作事件。多个菜单又可以组合成一个新的菜单增加在最顶层框架(JFrame)上,一般的窗口类都要创建菜单栏、多个菜单和一个菜单项。下拉式菜单如图522所示。 图522下拉式菜单的组成 (1) 一个菜单栏(JMenuBar)包含多个菜单,通过JFrame的setMenuBar方法加入一个JFrame中。一个菜单栏可以包含任意多个菜单对象,通过Add方法来增加菜单对象。 (2) 一个菜单(JMenu)是菜单项的集合,并且有一个标题,这个标题出现在菜单上,当单击这个标题时,这些菜单项立即弹出。使用它自身的add方法,可以增加菜单项(JmenuItem)或菜单(JMenu)对象。 (3) 菜单项在菜单中表示一个选项,并且可以注册一个动作监听器(ActionListener),以产生动作事件。 表59所示为JMenuBar、JMenu、JMenuItem的构造函数和常用方法。 建立菜单的步骤如下。 (1) 创建菜单栏对象,并将菜单条对象添加到窗体中。 JMenuBar mbar = new JMenuBar(); setJMenuBar(mbar);//窗体类Frame的方法 (2) 创建菜单对象,并将菜单对象添加到菜单栏中。 menu1=newJMenu("File"); menu2=newJMenu("Edit") mbar.add(menu1); mbar.add(menu2); 表59与JMenu相关的构造函数和常用方法 方法名功能 JMenuBar add(JMenu menu)创建菜单栏 在菜单栏中添加菜单 JMenu() JMenu(String label) add(JMenuItem mi) addSeparator() insert(JMenuItem mi, int index)创建菜单 创建具有指定标题内容的菜单 在菜单中添加菜单项 在菜单中添加一条分隔线 在菜单的指定位置插入菜单项 JMenuItem() JMenuItem(String label) getLabel() setLabel(String label) setEnabled(boolean b) addActionListener(ActionListener l)创建菜单项 创建具有指定标题内容的菜单项 获取菜单项的标题内容 设置菜单项的标题内容 设置菜单项是否可以选择 添加监视器,设置菜单项接收操作事件 (3) 创建菜单项对象,并将菜单项对象添加到相应的菜单中。 mi1=new JMenuItem("New"); mi2=new JMenuItem("Open"); mi3=new JMenuItem("Save"); mi4=new JMenuItem("Close"); menu1.add(mi1); menu1.add(mi2); menu2.add(mi3); menu2.add(mi4); 【例519】设计一个菜单程序。 这个程序包含“文件”和“编辑”菜单。菜单下又包含菜单项。“文件”菜单包含的菜单项为“新建文件”“打开文件”“退出”,“编辑”菜单包含的菜单项为“剪切”“复制”“粘贴”。除了“文件”和“退出”菜单项外,其他的所有的菜单项功能都暂时被关闭。 1/* 演示菜单程序 */ 2import javax.swing.*; 3import java.awt.event.*; 4public classExample5_19 extends JFrame implements ActionListener 5{JMenuItem fileNew = new JMenuItem("新建文件"); 6JMenuItem fileOpen = new JMenuItem("打开文件"); 7JMenuItem fileExit = new JMenuItem("退出"); 8JMenuItem editCut = new JMenuItem("剪切"); 9JMenuItem editCopy = new JMenuItem("复制"); 10JMenuItem editPaste = new JMenuItem("粘贴"); 11publicExample5_19() 12{super("菜单演示程序"); 13JMenu file = new JMenu("文件"); 14file.add(fileNew); fileNew.setEnabled(false); 15file.add(fileOpen); fileOpen.setEnabled(false); 16file.addSeparator(); 17file.add(fileExit);fileExit.setEnabled(true); 18JMenu edit = new JMenu("编辑"); 19edit.add(editCut);editCut.setEnabled(false); 20edit.add(editCopy);editCopy.setEnabled(false); 21edit.add(editPaste); editPaste.setEnabled(false); 22JMenuBar bar = new JMenuBar(); 23setJMenuBar(bar); 24bar.add(file); 25bar.add(edit); 26fileExit.addActionListener(this); 27setSize(250, 200); 28setVisible(true); 图523显示下拉式菜单 29setDefaultCloseOperation(EXIT_ON_CLOSE); 30} 31public void actionPerformed(ActionEvent e) 32{ 33if(e.getSource() == fileExit) 34System.exit(0); 35} 36public static void main(String args[]) 37{Example5_19 f = newExample5_19();} 38} 程序运行结果如图523所示。 菜单与按钮类似,两者都要产生动作事件。这两个组件几乎是所有GUI程序的标准组件。 5.5.2弹出式菜单 在窗体中,右击,弹出的菜单称为弹出式菜单,也称快捷菜单。弹出的菜单类JPopupMenu的构造方法和常用方法如下。 public JpopupMenu()//创建弹出式菜单对象 public JpopupMenu(String label)//创建带标识的弹出式菜单对象 void add(JMenuItem menuItem)//将指定菜单项添加到菜单 void addSeparator()//将分隔符添加到菜单 void show(Component invoker, int x, int y) //在组件invoker的坐标x、y处显示弹出式菜单 【例520】在文本框中显示弹出式菜单项。 1/* 右键弹出式菜单 */ 2import java.awt.*; 3import java.awt.event.*; 4import javax.swing.*; 5public class Example5_20 extends JFrame implements ActionListener 6{ 7JPopupMenu popup = new JPopupMenu(); 8JTextField txt = new JTextField(10); 9public Example5_21() 10{ 11super("右键弹出式菜单"); 12setSize(300,250); 13setVisible(true); 14setLayout(new FlowLayout()); 15add(txt); 16setDefaultCloseOperation(EXIT_ON_CLOSE); 17JMenuItem m1 = new JMenuItem("菜单项1"); 18JMenuItem m2 = new JMenuItem("菜单项2"); 19JMenuItem m3 = new JMenuItem("菜单项3"); 20JMenuItem m4 = new JMenuItem("菜单项4"); 21popup.add(m1); 22popup.add(m2); 23popup.add(m3); 24popup.addSeparator(); 25popup.add(m4); 26m1.addActionListener(this); 27m2.addActionListener(this); 28m3.addActionListener(this); 29m4.addActionListener(this); 30addMouseListener(new MouseAdapter() 31{ 32public void mouseClicked(MouseEvent e) 33{ 34if (e.getButton()==MouseEvent.BUTTON3) 35{ 36popup.show(e.getComponent(), 37e.getX(), 38e.getY()); 39} 40} 41}); 42validate(); 43} 44public void actionPerformed(ActionEvent e) 45{ 46txt.setText( 47((JMenuItem)e.getSource()).getText()); 48} 49public static void main(String args[]) 图524在文本框中显示弹出式菜单项 50{new Example5_20();} 51} 程序运行结果如图524所示。 5.5.3对话框 对话框(JDialog)是一个有边框、有标题且独立存在的容器,是一个从某个窗口弹出的特殊窗口。对话框与JFrame一样,不能被其他容器包容,不能作为程序的最顶层容器,也不能包含菜单。JDialog必须隶属于一个JFrame窗口,并由这个JFrame窗口负责弹出。如果它的父窗口JFrame消失,它也随之消失。 1. 对话框的构造 一般来说,对话框有两种类型,如下所述。 (1) “有模式”对话框(Medel Dialog): 当这个对话框处于激活状态时,只让程序响应对话框内部的事件,阻塞隶属父窗口对象的输入,而且它将阻塞其他线程的执行,直到该对话框被关闭。 (2) “无模式”对话框(Nonmodal Dialog): 这种对话框并不阻塞隶属父窗口对象的输入,可以与父窗口对象并存,除非特别声明,一般的对话框是“无模式”的。 一个对话框类使用如表510所示的4种构造方法进行初始化。 表510JDialog类的构造方法及其含义 构 造 函 数含义 JDialog(Type parent)创建以parent为父类的“无模式”对话框,parent可以为JFrame或JDialog JDialog(Type parent,Boolean modal)创建以parent为父对象对话框,parent可以为JFrame或JDialog JDialog(Type parent,String title)创建以parent为父类、title为标题的“无模式”对话框,parent可以为JFrame或JDialog JDialog(Type parent,String title, Boolean modal)创建以parent为父类、title为标题的对话框,parent可以为JFrame或JDialog 【例521】设计一个本对话框与窗口传递数据的程序。 1/* 本示例说明对话框与窗口传递数据 */ 2import java.awt.*; 3import java.awt.event.*; 4import javax.swing.*; 5class Win extends JFrameimplements ActionListener 6{ JButton btn1 = new JButton("打开对话框"); 7JTextArea txt = new JTextArea(5, 8); 8Win() 9{super("对话框与窗体传递消息"); 10setBounds(50, 50, 200, 200); 11setVisible(true); 12addWindowListener(new WindowAdapter(){ 13public void windowClosing (WindowEvent e){ 14System.exit(0); 15} 16} ); 17setLayout(new BorderLayout()); 18add(btn1, "North"); add(txt, "Center"); 19btn1.addActionListener(this); 20validate(); 21} 22public void actionPerformed(ActionEvent e){ 23Dia dia = new Dia(this, "传递消息对话框", true); 24dia.setVisible(true); 25txt.append(dia.getMessage()); 26} 27} 28//构造对话框类 29class Dia extends JDialog implements ActionListener 30{ 31JTextField txt = new JTextField(10); 32Dia(JFrame f, String s, boolean b){ 33super(f, s, b); 34setSize(300, 100); 35setLayout(new FlowLayout()); 36add(txt); 37txt.addActionListener(this); 38validate(); 39} 40public void actionPerformed(ActionEvent e){ 41setVisible(false); 42} 43//把对话框的消息传递出去 44public String getMessage(){ 45return txt.getText(); 46} 47} 48//主类 49public class Example5_21{ 50public static void main(String args[]) { 51new Win(); 52} 53} 程序运行结果如图525所示。 图525对话框传递消息给窗体 图526消息对话框基本外形 2. 消息对话框 Java有一种与用户交互操作的特殊消息对话框JOptionPane类,其基本外形通常如图526所示。 1) 消息对话框的构造方法 消息对话框的构造方法因其参数不同,所表现的形式有所不同,其常用构造方法如表511所示。 表511消息对话框的常用构造方法及其含义 构 造 方 法说明 JOptionPane()创建一个带有测试消息的JOptionPane对话框 JOptionPane(Object message)创建一个显示消息的JOptionPane对话框,提供默认选项 JOptionPane(Object message, int messageType)创建一个显示消息的JOptionPane对话框,使其具有指定的消息类型和默认选项 JOptionPane(Object message, int messageType, int optionType)创建一个显示消息的JOptionPane对话框,使其具有指定的消息类型和选项 JOptionPane(Object message, int messageType, int optionType, Icon icon)创建一个显示消息的JOptionPane对话框,使其具有指定的消息类型、选项和图标 其中: messageType定义消息对话框的样式。对话框的外观布置因此值而异,并提供默认图标。messageType取值为ERROR_MESSAGE、INFORMATION_MESSAGE、WARNING_MESSAGE、QUESTION_MESSAGE、PLAIN_MESSAGE。 optionType定义在对话框的底部显示的选项按钮的集合为DEFAULT_OPTION、YES_NO_OPTION、YES_NO_CANCEL_OPTION、OK_CANCEL_OPTION。 2) 消息对话框的静态方法 JOptionPane类通常调用静态方法showXxxxDialog()来确定对话框的显示类型,其方法如表512所示。 表512showXxxxDialog()显示对话框的类型 方法名说明 showConfirmDialog()确认对话框: 询问一个确认问题,如yes/no/cancel showInputDialog()输入对话框: 包括一个文本字段和两个按钮,确定和取消 showMessageDialog()消息对话框: 告知用户某事已发生 showOptionDialog()自定义格式对话框 例如,显示消息对话框类型,如图527所示。 JOptionPane.showMessageDialog(null, "提示的内容", "提示对话框", JOptionPane.ERROR_MESSAGE); 显示确认对话框类型,如图528所示。 JOptionPane.showConfirmDialog(null, "选择的内容", "选择对话框", JOptionPane.YES_NO_CANCEL_OPTION); 图527消息对话框 图528确认对话框 【例522】消息对话框示例。 1import javax.swing.*; 2public class Example5_22 3{ 4public static void main(String args[]) 5{ 6JOptionPaned_input = new JOptionPane(); 7String str = d_input.showInputDialog(null, "1+2=?"); 8if (str.equals("3")) 9d_input.showMessageDialog(null, "回答正确。"); 10else 11d_input.showMessageDialog(null, "回答错误!"); 12d_input.showConfirmDialog(null, "测试完毕!"); 13System.exit(0);//退出程序; 14} 15} 程序运行第7行输入对话框语句时,显示的结果如图529所示。 3. 文件选择对话框 实例化JFileChooser类后,调用showOpenDialog方法,能够打开一个文件选择对话框,可用于打开或保存文件时的文件选择,如图530所示。 JFileChooser file = new JFileChooser(); file.showOpenDialog(null); 图529“输入”对话框 图530文件选择对话框 【例523】文件选择对话框示例。 1import javax.swing.*; 2import java.awt.*; 3 4public class Example5_23 5{ 6public static void main(String args[]) 7{ 8JOptionPaned_input = new JOptionPane(); 9JFileChooser file = new JFileChooser(); 10file.showOpenDialog(null); 11String str = file.getSelectedFile().toString(); 12d_input.showMessageDialog(null, str); 图531显示返回所选择的文件 路径及文件名 13} 14} 运行程序后,显示图530中文件选择对话框,选择要打开的文件,返回所选择的文件路径及文件名,如图531所示。 4. 颜色选择对话框 实例化JColorChooser类后,调用showOpenDialog方法,能够打开一个颜色选择对话框,如图532所示。 JColorChoosercolor = new JColorChooser(); color.showDialog(null,"",null); 【例524】颜色选择对话框示例。 1import javax.swing.*; 2import java.awt.*; 3 4public class Example5_24 5{ 6public static void main(String args[]) 7{ 8JOptionPaned_input = new JOptionPane(); 9JColorChoosercolor = new JColorChooser() ; 10Color c = color.showDialog(null,"",null); 11d_input.showMessageDialog(null, c); 12} 13} 运行程序后,显示图532中的颜色选择对话框,选择颜色后,返回所选择颜色的值,如图533所示。 图532颜色选择对话框 图533显示返回所选颜色的值 5.6树 5.6.1树的概念 在Microsoft Windows文件管理器中,目录及文件都是以树状的层次结构显示出来的,就如同阶梯一般,一层包着一层,这样的做法不仅可以让用户清楚地了解各节点之间的关系,也使得用户在找寻相关的文件时更为方便。 图534树的结构 对于树的结构,最上层的点称为根节点(root node),在根节点下面的节点称为子节点(child node),子节点下面还可以有子节点,因此会形成所谓父节点与子节点的关系。每个节点可以有零个到多个的子节点。当一个节点没有任何的子节点时,就称这个节点为树叶节点(leaf node),反之称为树枝节点(internal node),其关系如图534所示。 节点A为根节点,节点B、C、D、E、F为A的子节点。节点C是节点D、E、F的父节点,节点D、E、F是节点C的子节点。节点B、D、E、F为树叶节点,节点A、C为树枝节点。 在Java中,JTree是建立树结构的类。初始状态的树状视图,在默认情形下,只显示根节点和它的直接子节点。用户可以双击分节点的图标或单击图标前的“开关”使该节点展开或收缩。 5.6.2树的构造方法 1. 树的创建 可以使用JTree类的构造方法创建树。JTree的常用构造方法如下。  JTree(): 建立一个系统默认的树。  JTree(Hashtable value): 应用Hashtable表建立树,不显示根节点。  JTree(Object[] value): 应用数组Object[]建立树,不显示根节点。  JTree(TreeNode root): 应用节点TreeNode建立树。  JTree(TreeNode root, boolean askAllowsChildren): 应用节点TreeNode建立树,并确定是否允许有子节点。 【例525】建立一个系统默认的简单树结构。 1/* 最简单的JTree示例 */ 2import java.awt.*; 3import javax.swing.*; 4class TreeDemo extends JFrame 5{ 6public TreeDemo() 7{ 8setSize(400,300); 9setTitle("演示怎样使用JTree"); 10show(); 11JScrollPane jPanel = new JScrollPane(); 12getContentPane().add(jPanel); 13//创建系统默认的树状对象 14JTree jtree = new JTree(); 15//在面板上添加树状结构 16jPanel.getViewport().add(jtree, null); 17validate(); 18//设置"关闭窗口"按钮 19setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 20} 21} 22//主类 23public class Example5_25 24{ 25public static void main(String args[]) 26{ 27TreeDemo frame = new TreeDemo(); 28} 29} 【程序说明】 本程序非常简单,利用JTree()构造了一个系统默认的树对象,并将些对象放在带滚动条的面板JScrollPane中,当树结构大于窗体空间时,可以利用滚动条来滚动面板。 程序运行结果如图535所示。 图535系统默认的简单树结构 2. 树节点的创建 例525虽然简单,但并没有多少实质意义,因为各个节点的数据都是Java的默认值,而非用户定义的数据。树结构的类是JTree,要构造一个由用户定义枝节点的树,JTree必须同树枝节点类TreePath和TreeNode共同来完成。 树节点由javax.swing.tree包中的接口TreeNode定义,该接口是MutableTreeNode类的子类,而MutableTreeNode又由DefaultMutableTreeNode类实现,因此,在创建树时,要使用DefaultMutableTreeNode类为该树创建节点。 DefaultMutableTreeNode类的常用构造方法是: DefaultMutableTreeNode(Object userObject); DefaultMutableTreeNode(Object userObject, boolean allowChildren); 第一个构造方法创建的节点默认可以有子节点,即它可以用add方法添加其他节点作为它的子节点。 对于一个节点,可以使用方法setAllowsChildren(boolean b)来设置是否允许有子节点。 应用节点TreeNode构造树的步骤如下: (1) 定义节点。 DefaultMutableTreeNode n1=new DefaultMutableTreeNode("节点1"); DefaultMutableTreeNode n2=new DefaultMutableTreeNode("节点2"); DefaultMutableTreeNode n3=new DefaultMutableTreeNode("节点3"); … (2) 定义树,同时确定n1为根节点。 JTree tree=new JTree(n1); (3) 添加子节点。 n1.dd(n2); n1.add(n3); 【例526】建立一个应用TreeNode构造如图536所示结构的树。 图536TreeNode树结构 1/* "利用TreeNode构造树" */ 2import javax.swing.*; 3import javax.swing.tree.*; 4import java.awt.*; 5import java.awt.event.*; 6class Mytree extends JFrame 7{ 8Mytree(String s) 9{ 10super(s); 11Container con=getContentPane(); //定义JFrame窗体容器 12//定义节点 13DefaultMutableTreeNode root=new DefaultMutableTreeNode("c:\\"); 14DefaultMutableTreeNode t1=new DefaultMutableTreeNode("备份资料"); 15DefaultMutableTreeNode t2=new DefaultMutableTreeNode("Java学习"); 16DefaultMutableTreeNode t1_1=new DefaultMutableTreeNode( 17"思维论坛精华帖子"); 18DefaultMutableTreeNode t1_2=new DefaultMutableTreeNode("来往邮件"); 19DefaultMutableTreeNode t2_1=new DefaultMutableTreeNode("视频教程"); 20DefaultMutableTreeNode t2_2=new DefaultMutableTreeNode("Java3D"); 21//创建根节点为root的树 22 JTree tree=new JTree(root); 23//定义t1、t2为root的子节点 24root.add(t1); 25root.add(t2); 26//定义t1_1,t1_2为t1的子节点 27t1.add(t1_1);t1.add(t1_2); 28//定义t2_1,t2_2为t2的子节点 29t2.add(t2_1); 30t2.add(t2_2); 31JScrollPane scrollpane=new JScrollPane(tree); //带滚动条的面板(树放置其中) 32con.add(scrollpane); 33setSize(300,200); 34setVisible(true); 35validate(); 36setDefaultCloseOperation(EXIT_ON_CLOSE); 37} 38} 图537利用TreeNode构造树 39//主类 40public class Example5_26 41{ 42public static void main(String[] args) 43{ 44new Mytree("利用TreeNode构造树"); 45} 46} 程序运行结果如图537所示。 3. 利用哈希表构造树 在下面的例子中,介绍利用哈希表(Hash table)的数据来建立树结构。 【例527】建立一个利用哈希表数据构造树的结构。 1/* 利用哈希表定义树结构 */ 2import java.awt.*; 3import java.awt.event.*; 4import javax.swing.*; 5import java.util.*; 6//定义树结构类 7class TreesDemo //extends JPanel 8{ 9public TreesDemo() 10{ 11JFrame f = new JFrame("哈希表定义树结构演示"); 12Hashtable hashtable1 = new Hashtable(); 13Hashtable hashtable2 = new Hashtable(); 14String[] s1={"思维论坛","Java爱好者","网上书店"}; 15String[] s2={"公司文件","私人文件","往来信件"}; 16String[] s3={"本机磁盘(C:)","本机磁盘(D:)","本机磁盘(E:)"}; 17hashtable1.put("桌面",hashtable2); 18hashtable2.put("收藏夹",s1); 19hashtable2.put("我的公文包",s2); 20hashtable2.put("我的电脑",s3); 21//树进行初始化,其数据来源是root对象 22JTree tree=new JTree(hashtable1); 23JScrollPane scroll = new JScrollPane(); 24scroll.setViewportView(tree); 25Container con = f.getContentPane(); 26con.add(scroll); 27f.setSize(200,300); 28f.setVisible(true); 29f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 30} 31} 32//主类 33public class Example5_27 { 34public static void main(String args[]) 35{ TreesDemo jf=new TreesDemo();} 36} 图538利用哈希表数据 建立树结构 【程序说明】 哈希表是常用的数据结构,它是利用keyvalue对的方式来存储数据,也就是说当要在哈希表中找寻数据时,必须先提供关键字key的值,哈希表会根据key值找到所关联的数据项值value。哈希表是利用put方法将keyvalue对放入哈希表中。程序第17行中,“收藏夹”就是一个key值,而字符串数组s1的数据“思维论坛”“Java爱好者”“网上书店”是“收藏夹”对应的数据项value值。 程序运行结果如图538所示。 4. 处理节点事件 树中的节点可以发生选择事件,即单击节点时产生事件。一个树对象处理事件的接口是TreeSelectionListener,可以使用: 树对象.addTreeSelectionListener(this); 方法获得一个监视器。 树对象通过使用方法getLastSelectedPathComponent获取选中的节点,使用方法getUserObject得到与节点相关的信息。 【例528】处理节点事件。 1/* 处理节点事件 */ 2import java.awt.*; 3import java.awt.event.*; 4import javax.swing.*; 5import javax.swing.tree.*; 6import javax.swing.event.*; 7//定义树结构类 8class TreesDemo extends JFrame implements TreeSelectionListener 9{ 10JTree tree=null; 11JTextArea text=new JTextArea(20,20); 12public TreesDemo() 13{ 14super("处理节点事件"); 15Container con=getContentPane(); 16String[][] data={ 17{"我的电脑","本机磁盘(C:)","本机磁盘(D:)","本机磁盘(E:)"}, 18{"收藏夹","思维论坛","Java爱好者","网上书店"}, 19{"我的公文包","公司文件","私人文件","往来信件"}, 20}; 21DefaultMutableTreeNoderoot;//定义根节点 22DefaultMutableTreeNodetreeNode[][]; //定义节点数组 23//建立根节点对象 24root=new DefaultMutableTreeNode("桌面"); 25//声明节点数组容量 26treeNode=new DefaultMutableTreeNode[4][4]; 27//外循环建立父节点,内循环建立子节点 28for (int i=0;i