·本章学习目标
了解如何创建GUI程序。
掌握使用常见布局管理器构建复杂的布局。
掌握事件类,事件接口和事件适配器。
了解组件的概念及组件的多种子类的用法。
掌握Swing组件的基本用法。
·本章学习内容
本章的主要内容是如何使用Java的组件构建图形用户界面(GUI),若要正确地设计图形用户界面,还要涉及到组件的布局与事件处理。本章要学习的知识点包括:
图形用户界面组件——AWT组件、Swing组件
容器的概念及用容器类
布局设计及几种常见的布局管理器
GUI的事件处理
5.1 图形用户界面设计与AWT组件
Windows操作系统中使用的都是图形用户界面(GUI),要在Java中实现GUI,可通过如下过程来创建一个GUI元素:
(1)创建组件,如复选框、列表框、标签等;
(2)确定其初始外观;
(3)确定它应占一个特定位置还是任一缺省位置;
(4)将其添加至屏幕界面。
Java基本类库(Java Fundation Class, JFC)是Java 2核心API的重要组成部分。它包括四个部分:Swing组件、Java 2D、拖放API和可访问性API。
5.1.1 AWT组件
AWT(Abstract Window ToolKit,抽象窗口工具包)是一组用于设计GUI的Java库函数,位于java.awt包中。它包括以下内容:
(1)便于用户输出的一组丰富的界面组件;
(2)将组件放置到屏幕上适当位置的布局管理器;
(3)事件处理模型;
(4)图形和图像工具;
(5)和本地平台剪贴板操作一起使用的几个类。
5.1.2容器、组件和布局
组件是显示在屏幕上并能和用户进行交互的图形对象。例如常见的命令按钮、列表框、滚动条、位图等都是组件,在使用时应该放在容器中。java.awt包中包含一个Component类。
容器是用来存放组件的区域,在容器上可以绘图和着色。java.awt包中包含一个Container类。容器是用来存放组件的,而组件的位置摆放就要使用一些部件管理器来完成这个任务了。
5.1.3顶级容器Frame和中间容器Panel
1、窗体(Frame)
Frame窗体是独立于Applet和浏览器的一个窗口,可以用作容器或组件。Frame类是Window类的子类,封装了窗口中通用的一切组件,并且拥有标题栏、菜单栏、边框和调整大小的角。
Frame类的构造方法如下:
Frame() //创建一个不含标题的标准窗口
Frame(String title) //创建标题名为title的标准窗口
【例1】使用Frame类创建一个窗体。
import java.awt.*;
class FrameDemo {
public static void main(String args[ ]){
Frame f = new Frame();
//Frame f = new Frame (“带边框的窗体”);
f.setSize(300,200);
f.setVisible(true);
}
}
2、面板(Panel)
Panel是包含在Frame中的一个区域,它是可以将许多组件组合起来的一种容器,也可看作是不含标题栏、菜单栏及边框的窗口。Panel是Container类的一个子类,只是简单的实现了Container类。通过构造方法Panel()即可创建面板。
【例2】创建一个面板。
import java.awt.*;
class PanelTest extends Panel {
public static void main(String args[ ]){
PanelTest p = new PanelTest();
Frame f = new Frame (“正在测试面板”);
f.add(p);
f.setSize(300,200);
f.setVisible(true);
}
}
5.2 布局管理器
组件在容器中摆放的方式叫做布局。在前面的程序中提及布局问题,实际是采用了一种默认的布局。本节介绍几种常用的布局管理器。
5.2.1 FlowLayout布局
FlowLayout布局就是按行布局。组件按照添加的顺序从左到右逐个摆放在容器上,排满了一行再排下一行。Applet类和Panel类默认的布局就是FlowLayout。
创建FlowLayout布局使用的构造方法如表5-39所示。
FlowLayout布局的构造方法
构造方法
|
解释
|
FlowLayout()
|
创建一个默认的FlowLayout布局。具体的做法是以居中的方式,水平和竖直间距为5个单位
|
FlowLayout(int align)
|
用参数align指定的对齐方式创建一个FlowLayout布局,水平和竖直间距为5个单位。align可取值为以下静态常量:
static int CENTER 居中
static int LEFT 左对齐
static int RIGHT 右对齐
|
FlowLayout(int align, int hgap, int vgap)
|
用参数align指定的对齐方式,参数hgap指定的水平间距,参数vgap指定的竖直间距创建一个FlowLayout布局
|
5.2.2 GridLayout布局
GridLayout布局即网格布局,是将容器划分为若干行列的网格,每一个格中放置一个组件,通常是从左到右、从上到下逐行放置的,若要改变放置的方向应当利用ComponentOrientation类来实现。放置时每一个组件的大小都是相同的,如果添加的个数少于网格的个数,就会产生空白,如果添加的个数多于网格的个数,系统会自动增加列数以满足需要。
创建GridLayout布局使用的构造方法如表5-39所示。
GridLayout布局的构造方法
构造方法
|
解释
|
public GridLayout()
|
创建一个默认的GridLayout布局。具体的做法是添加的所有组件都占据仅有的一行
|
public GridLayout( int rows, int cols)
|
用参数rows指定的行数和参数cols指定的列数创建一个GridLayout布局。如果两个参数中有一个为0,则表示这个参数是任意个数的。但是二者不能同时为0,那样会引起难料的后果
|
public GridLayout( int rows, int cols, int hgap, int vgap )
|
用参数rows指定的行数、参数cols指定的列数、参数hgap指定的水平间距和参数vgap指定的竖直间距创建一个GridLayout布局
|
【例】GridLayout应用。
import java.awt.*;
import java.swing.*;
public class GridEx{
public static void main(String args[]){
JFrame jf = new JFrame(“Grid Example”);
jf.setLayout(new GridLayout(2,2));
jf.add(new JButton(“1”)); jf.add(new JButton(“2”));
jf.add(new JButton(“3”)); jf.add(new JButton(“4”));
jf.setVisible(true);
}
}
5.2.3 GridBagLayout布局
GridBagLayout布局即网格包布局,是在GridLayout布局的基础上改进发展而来的,只是比GridLayout布局更灵活,使用起来也要复杂一些。使用GridBagLayout布局涉及到GridBagLayout类和GridBagConstraints类两个类。
GridBagLayout类和GridBagConstraints类的构造方法和常用成员方法见下页。
GridBagLayout类的常用方法
构造方法
|
解释
|
public GridBagLayout ( )
|
创建一个GridBagLayout布局
|
常用方法
|
解释
|
public void setConstraints(Component comp, GridBagConstraints constraints)
|
设置布局中参数comp指定的组件的约束条件为constraints
|
GridBagLayout类的构造方法
构造方法
|
解释
|
public GridBagConstraints ()
|
创建一个GridBagLayout布局的约束条件对象
|
成员变量
|
解释
|
static int RELATIVE
|
指定组件在行或列的方向上与最后一个组件或刚加入的组件相邻
|
static int REMAINDER
|
指定组件是行或列的方向上的最后一个组件
|
int fill
|
fill成员变量规定填充方式,具体可取以下常量:
GridBagConstraints.NONE 不改变组件的大小,此为默认值
GridBagConstraints.HORIZONTAL使组件的宽度变得足够大以添满水平方向的间隙,但不改变竖直方向的高度GridBagConstraints.VERTICAL使组件的高度变得足够大以添满竖直方向的间隙,但不改变水平方向的宽度GridBagConstraints.BOTH 使组件的宽度和高度都变得足够大以添满水平方向和竖直方向的间隙
|
int gridheight
|
组件竖直方向上含有的格数
|
int gridwidth
|
组件水平方向上含有的格数
|
5.2.4 BorderLayout布局
BorderLayout布局称为边界布局。具体的布局方法是把容器划分成北north、南south、东east、西west、中center 共5个区域,向容器添加组件时用参数指明添加到哪个区域。如果某一个区域没有添加组件,相邻的组件将占据这一区域的位置,例如若北部没有分配组件,则东、西、中部中的组件将向上延伸,占据北部的位置;若东、西部没有分配组件则中部组件将向两侧延伸占据东、西部的位置。
BorderLayout布局的构造方法
构造方法
|
解释
|
public BorderLayout()
|
创建一个默认的BorderLayout布局,默认的水平间距和竖直间距都是0,即各个组件是彼此紧密相邻的
|
public BorderLayout (int hgap, int vgap)
|
用参数hgap指定的水平间距和参数vgap指定的竖直间距创建一个BorderLayout布局
|
5.2.5 CardLayout布局
CardLayout布局称为卡片布局,它可以存储不同的布局,每个布局就像一个卡片组中的一张卡片,每次总会有一张卡片在顶层。卡片通常为一个Panel对象。
实现CardLayout布局的步骤如下:
定义面板,为各面板设置不同的布局;
panelOne.setLayout(new FlowLayout());
panelTwo.setLayout(new GridLayout(2,1));
将主面板设置为CardLayout;
panelMain.setLayout(new CardLayout());
将各面板添加至主面板。
panelMain.add(“面板1”,panelOne);
panelMain.add(“面板2”,panelTwo);
5.2.6 null布局
null布局就是没有布局,用户可以充分利用Component类的setBounds方法自行布局,灵活性很大。
setBounds(int x, int y, int width, int height):移动组件并调整其大小。
5.3 Swing组件体系结构
由于AWT提供的GUI组件太有限且比较粗糙,开发大型的应用程序时不能满足要求,同时效率比较低。
Swing有一个与平台无关的实现,Swing是AWT的扩展,它提供了许多新的图形界面组件。Swing组件以"J"开头,除了有与AWT类似的按钮(JButton)、标签(JLabel)、复选框(JCheckBox)、菜单(JMenu)等基本组件外,还增加了一个丰富的高层组件集合,如表格(JTable)、树(JTree)。可以说Swing很大程度上取代了AWT来完成GUI的创建。下面详细介绍Swing应用程序中常用的各种组件的用法。
5.3.1窗体JFrame
JFrame用于在Swing程序中创建窗体,它扩展了java.awt.Frame类。JFrame类的构造方法如下:
JFrame(); JFrame(String title);
在JFrame中添加组件的步骤:
先调用Container类的getContentPane()方法来产生一个Container对象;
然后使用Container对象的add()方法来添加组件。
【例3】在Swing组件中创建一个窗体窗口。
import java.awt.*;
import javax.swing.*;
public class FrameDemo extends JFrame {
public FrameDemo(String title) {
super(title);
}
public static void main(String args[ ]) {
FrameDemo fd = new FrameDemo(“JFrame 测试”);
fd.setVisible(true);
fd.setSize(300,200);
}
}
5.3.2面板JPanel
JPanel组件是中间容器,用于将轻量级组件组合在一起,JPanel对象的默认布局为FlowLayout。其构造方法如下:
JPanel(); JPanel(LayoutManager lm);
JPanel类的大部分方法都是派生自其父类:JComponent,Container和Component。
【例4】在Swing组件中加入一个JPanel窗口。
import java.awt.*;
import javax.swing.*;
public class PanelDemo extends JFrame {
public PanelDemo(String title) {
super(title);
Container c = getContentPane();
JPanel cpane = new JPanel();
JButton ok = new JButton(“确定”);
cpane.add(ok);
JButton cancel = new JButton(“取消”);
cpane.add(cancel);
c.add(cpane,BorderLayout.SOUTH);
}
public static void main(String args[ ]) {
PanelDemo pd = new PanelDemo(“JPanel测试”);
pd.setVisible(true);
pd.setSize(300,200);
}
}
5.3.3标签JLabel
JLabel类是JComponent类的子类,它既可以显示文本,也可以显示图像。其构造方法如下:
JLabel(); JLabel(Icon icon);icon表示使用的图标。
JLabel(String text,Icon icon, int align);text表示使用的字符串;icon表示使用的图标;align表示水平对齐方式,其值可以是LEFT、RIGHT和CENTER。
【例5】在Swing组件中加入一个JLabel标签。
import java.awt.*;
import javax.swing.*;
public class PanelDemo extends JFrame {
public PanelDemo(String title) {
super(title);
Container c = getContentPane();
JPanel cpane = new JPanel();
JLabel my_label = new JLabel();
my_label.setText(“标签测试”);
cpane.add(my_label);
c.add(cpane,BorderLayout.SOUTH);
}
}
5.3 Swing组件体系结构
public static void main(String args[ ]) {
PanelDemo pd = new PanelDemo(“标签测试”);
pd.setVisible(true);
pd.setSize(300,200);
}
}
5.3.4按钮JButton
JButton派生自javax.swing.AbstractButton类,JButton类允许用图标,字符串或两者同时构造一个按钮。其构造方法如下:
JButton(); JButton(Icon icon);
JButton(String text,Icon icon);
Icon表示使用的图标,text表示使用的字符串。按钮上的文本可包含一个带下划线的字母,表明此按钮的键盘快捷键。
【例6】JButton的用法。
import java.awt.*;
import javax.swing.*;
public class ButtonDemo extends JPanel {
JButton b1,b2;
public ButtonDemo() {
b1 = new JButton(“firstButton”);
b2 = new JButton(“secondButton”);
add(b1);
add(b2);
}
public static void main(String args[ ]) {
JFrame jf = new JFrame(“按钮测试!”);
jf.getContentPane().add(new ButtonDemo());
jf.setSize(300,200);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame. EXIT_ON_CLOSE);
}
}
5.3.5文本组件
文本组件对GUI很重要,JTextComponent是所有Swing文本组件的根类。它包含JTextField组件、JTextArea组件、jPasswordField组件等。
1、JTextField——允许输入或编辑单行文本。构造函数如下:
JTextField();
JTextField(Document doc, String text,int columns);
JTextField(int columns);
JTextField(String text);
JTextField(String text,int columns);
【例7】创建一个单行文本。
import java.awt.*;
import javax.swing.*;
public class TextFieldDemo extends JFrame {
public TextFieldDemo() {
Container con = getContentPane();
con.setLayout(new FlowLayout());
JLabel jl = new JLabel(“文本域”);
con.add(jl);
setSize(300,200);
setVisable(true);
}
public static void main(String args[ ]) {
new TextFieldDemo();
}
}
2、JTextArea——用于接收来自用户的多行文本。它本身不处理滚动,但可以实现滚动界面,此界面允许被置于JScrollpane内部,并据此实现滚动。其构造方法如下:
JTextArea();
JTextArea(Document doc);
JTextArea(Document doc,String text,int rows,int cols);
JTextArea(int rows,int cols);
JTextArea(String text);
JTextArea(String text,int rows,int cols);
【例8】JTextArea对象的用法。
import java.awt.*;
import javax.swing.*;
public class TextAreaDemo extends JFrame {
public TextAreaDemo() {
Container con = getContentPane();
con.setLayout(new FlowLayout());
JLabel jl = new JLabel(“文本区”);
con.add(jl);
JTextArea ta = new JTextArea(5,10);
con.add(ta);
setSize(300,200);
setVisable(true);
}
public static void main(String args[ ]) {
new TextAreaDemo();
}
}
5.3.6复选框JCheckBox
JCheckBox是可以打开或关闭它以选择某个选项的组件,用在Swing中创建复选框。其构造方法如下:
JCheckBox();
JCheckBox(Icon icon);
JCheckBox(Icon icon , Boolean selected);
JCheckBox(String text);
JCheckBox(String text , Boolean selected);
JCheckBox(String text,Icon icon);
JCheckBox(String text,Icon icon , Boolean selected);
5.3.6复选框JCheckBox
【例9】JCheckBox的用法。
5.3.7单选按钮JRadioButton
一组单选按钮用于显示多个选项,但用户只能选择其中一个。ButtonGroup用于在Swing中创建这样的组。其构造方法如下:
JRadioButton(); JRadioButton(Icon icon);
JRadioButton(Icon icon , Boolean selected);
JRadioButton(String text); JRadioButton(String text , Boolean selected);
JRadioButton(String text,Icon icon); JRadioButton(Action a);
JRadioButton(String text,Icon icon , Boolean selected);
【例10】 JRadioButton的用法。
import java.awt.*;
import javax.swing.*;
public class JRadioButtonDemo extends JFrame {
public JRadioButtonDemo() {
Container con = getContentPane();
con.setLayout(new FlowLayout());
JRadioButton jrb1 = new JRadioButton(“男”);
JRadioButton jrb2 = new JRadioButton(“女”);
ButtonGroup bg = new ButtonGroup();
con.add(new JLable(“性别”));
con.add(jrb1);
con.add(jrb2);
bg.add(jrb1);
bg.add(jrb2);
setSize(300,200);
setVisible(true);
}
public static void main(String args[ ]) {
new JRadioButtonDemo();
}
}
5.3.8列表JList
Swing提供了一个非常复杂的列表组件JList,编程时可以使用字符串列表,也可以使用任意对象构成的列表。其构造方法如下:
public JList(); 使用空模型构造Jlist
public JList(ListModel dataModel); 构造一个模型,让它显示制定模型中的元素
public JList(Object[ ] listData); 构造一个列表以显示指定数组listData中的元素
【例10】JList的用法。
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
class AllStars extends JFrame implements ListSelectionListener {
String stars[ ] = {"成龙","刘德华","赵薇","刘若英","周华健"};
JList moviestars = new JList(stars);
JLabel lblask = new JLabel("您最喜欢哪位演员?");
JTextField jt = new JTextField(30);
public AllStars(String s) {
super(s);
JPanel p = (JPanel)getContentPane();
p.setLayout(new BorderLayout());
p.add("North",lblask);
moviestars.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
moviestars.setSelectedIndex(0);
moviestars.addListSelectionListener(this);
moviestars.setBackground(Color.lightGray);
moviestars.setForeground(Color.black);
p.setBackground(Color.white);
p.setForeground(Color.black);
p.add("Center",new JScrollPane(moviestars));
p.add("South",jt);
pack();
}
public static void main(String args[ ]) {
AllStars s = new AllStars("群星璀璨!");
s.setSize(400,400);
s.show();
}
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) {
if (moviestars.getSelectedIndex() != -1) {
jt.setText((String)moviestars.getSelectedValue());
}
}
}
}
JList不支持滚动。为创建滚动列表,JList以JScorllPane实现。实现代码如下:
JScorllPane myScorllPane = new JScorllPane();
myScorllPane.getViewport().setView(dataList);
或者
JScorllPane myScorllPane = new JScorllPane(dataList);
JList不提供处理鼠标双击或三击的特殊支持,但是使用MouseListener很容易就可以处理这些事件。locationToIndex()方法用于确定单击的单元。
5.3.9其他Swing组件
比较重要的Swing组件还有表格JTable、滚动条JScrollBar、树JTree和菜单组件等等。其功能及使用方法与前面介绍的Swing组件基本类似,而且我们的NetBeans开发环境可以实现手动拖放组件,所以这里就不再具体介绍这些组件。
5.4 事件处理Event
5.4.1事件类AWTEvent
Java使用的是基于授权事件模型的事件处理方法,即一个源产生一个事件并把它送到一个或多个监听器,监听器只需等待,直到收到一个事件,监听器将处理这些事件,然后返回。
Java通过ActionEvent、WindowEvent等事件类处理事件。这些类的父类都是java.awt包中的AWTEvent类。AWTEvent类的层次结构。
java.lang.Object包
|
|
Java.untl.EventObject类
|
|
AWTEvent事件类
|
|
ActionEvent按钮单击事件
|
ComponentEvent组件事件
|
|
ContainerEvent容器事件
|
FocusEvent焦点事件
|
InputEvent输入事件
|
|
KeyEvent键盘事件
|
MouseEvent鼠标事件
|
WindowEvent窗口事件
|
ItemEvent选择事件
|
TextEvent文本框事件
|
对于每一个事件,在进行相应的处理时必须知道该事件是哪一个组件产生的,Java的EventObject类提供了getSource方法用于获取产生事件的组件对象,而ActionEvent类提供了getActionCommand方法用于获取产生事件的按钮的标签,下表是这两个方法的语法格式。
事件处理的常用方法
常用方法
|
解释
|
public Object getSource( )
|
获取产生事件的组件
|
public String getActionCommand( )
|
获取按钮的标签
|
在Java的java.awt.event包中,每个事件类都有一个对应的接口,并在接口中定义了若干个抽象的事件处理方法。若要接受并处理某一个事件类,必须实现相应的接口,这些接口名都是以Listener为后缀的。
根据Java对接口的规定,实现接口时必须重写接口中的所有抽象方法,如果并不需要某一个方法,也要为该方法建立一个方法体为空的方法。
5.4.2事件类的接口interface
事件监听器(事件类)
|
方法
|
说明
|
ActionListener单击事件接口(ActionEvent单击事件类)
|
actionPerformed
|
当一个操作事件发生时将调用此方法。
|
AdjustmentListener调整焦点事件接口(AdjustmentEvent调整事件类)
|
AdjustmentValueChanged
|
当发生调整事件时将调用此方法。
|
ComponentListener组件事件接口(ComponementEvent组件事件类)
|
componentResized
componentMoved
componentshown
componentHidden
|
当组件改变大小、移动、显示或隐藏时分别调用这些方法。
|
ContainerListener调整焦点事件接口(ContainerEvent调整事件类)
|
componentAdded
componentRemoved
|
当将组件添加到容器时将调用上一方法,将组件从容器中删除时将调用下一方法。
|
FocusListener调整焦点事件接口(FocusEvent调整事件类)
|
FocusGained
FocusLost
|
当组件获得键盘焦点时将调用上一方法,将组件失去键盘焦点时将调用下一方法。
|
ItemListener选择事件接口(ItemEvent选择事件类)
|
itemStateChanged
|
当单击复选框或列表项,或项目状态改变时调用此方法
|
KeyListener键盘事件接口
(KeyEvent键盘事件类)
|
keyPressed
keyReleased
keyTyped
|
当按下、释放按键时分别调用前两个方法;而输入字符时将调用第三个方法
|
MouseListener鼠标按钮事件接口(MouseEvent鼠标事件类)
|
mouseClicked
mouseEntered
mouseExited
mousePressed
mouseReleased
|
当按下并立即释放鼠标时将调用第一个方法;鼠标进入、离开组件时将分别调用第二、三个方法;当按下、释放鼠标时分别调用地四、五个方法
|
MouseMotionListener鼠标移动事件接口(MouseEvent鼠标事件类)
|
mouseDragged
mouseMoved
|
当拖动或移动鼠标时
|
TextListener文本框事件接口(TextEvent文本框事件类)
|
textValueChanged
|
文本行或文本区中中的文本别修改时将调用此方法
|
WindowListener窗口事件接口(WindowEvent窗口事件类)
|
windowOpened
windowActivated
windowDeactivated
windowClosing
windowClosed
windowIconified
windowDeiconified
windowStateChanged
|
当一个窗口被打开、激活、禁止、正在关闭、关闭、最小化、恢复、窗口状态变化时依次调用这些方法
|
实现接口时必须重写接口中的所有方法,这给编程带来了不便。为此Java提供了事件适配器。事件适配器是一种特殊的类,都具有Adapter后缀,适配器实现了接口的所有方法,这样在创建新类时就可以不实现接口,而是转而继承相应的适配器,继承适配器以后,只需重写用户用到的方法。下表是接口与适配器的对应关系。
5.4.3事件适配器Adapter
事件接口
|
事件适配器
|
ComponentListener组件事件接口
|
ComponentAdapter组件事件适配器
|
ContainerListener容器事件接口
|
ContainerAdapter容器事件适配器
|
FocusListener焦点事件接口
|
FocusAdapter焦点事件适配器
|
KeyListener键盘事件接口
|
KeyAdapter键盘事件适配器
|
MouseListener鼠标按钮事件接口
|
MouseAdapter鼠标按钮事件适配器
|
MouseMotionListener鼠标移动事件接口
|
MouseMotionAdapter鼠标移动事件适配器
|
WindowListener窗口事件接口
|
WindowAdapter窗口事件适配器
|
·小结
由于用户界面设计在程序设计中的重要地位,决定了本章内容的重要性。在本章中的重点是:组件类及其子类(按钮组件、文本组件、标签组件、复选框和单选钮组、选择框和列表框、滚动条等);事件类及其针对具体事件的子类,事件接口和事件适配器;容器类及其子类(框架类、面板类、对话框类等);布局类及其子类;颜色类和字体类;下拉菜单和弹出式菜单。