第11章 GUI程序设计
11.1 JFC简介
JFC(Java Foundation Class) 作为CUI(Graphic User Interface)设计的基础.JFC包含AWT(Abstract Window Toolkit),Swing和Java2D
Swing相对于AWT的优点:
1:Swing不在依赖于运行时的本地组件,它完全是用Java编写的,从而解决了AWT中存在的可移植的问题
2:Swing具有可拔插的外观风格,即通过在几种预先配置好的外观风格中进行选择,可以让GUI程序显示出不同的外观风格
3:Swing采用的是MVC模式.更灵活
11.2 Swing组件的结构
1:顶层容器:JApplet,JDialog,JFrame 和JWindow及其子类
2:MVC结构
11.3:顶层容器
11.3.1:JFrame
JFrame 是最常用的一种顶层容器,它的作用是创建一个顶层的Windows窗体.JFrame的外观就像平常的Windows系统下见到的窗体,有标题,边框,菜单.
public class JFrameDemo extends JFrame
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setSize(300, 300);// 设置窗体大小
frame.setLocation(400, 400);// 设置窗体显示的位置
frame.setTitle("JFrameDemo");// 设置窗体的标题frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 设置关闭按键的默认操作
frame.setVisible(true);// 显示窗体
}}
11.3.2 JDialog,JWindow和JApplet
JDialog是创建对话框的顶层容器类,它与JFrame的不同之处在于对话框没有最大化和最小化按钮.JWindow 也可以创建一个窗体,没有标题栏,最大化和最小化,Applet是一种能够嵌入到网页执行的Java图形程序
11.4:布局管理
Swing采用了两种布局方式:无布局管理器布局和基于布局管理器的布局.后者是Swing为了实现跨平台的动态布局效果而提出的布局方式.在设置时,我们需要调用setLayout方法,布局管理器有:FlowLayout,BorderLayout,GridLayout等多种方式.
11.4.1:无布局管理器布局
Swing提供了setLocation(),setSize(),setBounds()等布局方法,但Swing的组件中存在一个默认的布局管理器,因此这些设置方法都会失效.如果需要设置组件大小或位置,则应取消该容器的布局管理器,方法为调用setLayout方法,并将布局管理器设置为null 举例代码如下:
public class AbsoluteLayout extends JFrame
{
public static void main(String[] args)
{
AbsoluteLayout aLayout = new AbsoluteLayout();
aLayout.setVisible(true);
}
private JButton button = new JButton("JButton");// 创建button
private JTextField textField = new JTextField("JTextField");// 创建输入字符段
public AbsoluteLayout()
{
setSize(300, 300);
setLocation(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(null);// 设置布局管理null
this.button.setLocation(20, 20);
this.button.setSize(100, 20);
add(this.button);
this.textField.setBounds(20, 50, 200, 100);// 设置输入框的位置为(20,50),宽200高100
add(this.textField);
}}
11.4.2:FlowLayout 规律是从左到右,从上到下进行放置,变化规律是:组件的大小不变,但是其相对位置会发生改变
public class FlowLayoutDemo extends JFrame
{
public static void main(String[] args)
{
FlowLayoutDemo fLayoutDemo = new FlowLayoutDemo();
fLayoutDemo.setVisible(true);
}
private JButton button1 = new JButton("first button");
private JButton button2 = new JButton("second button");
private JButton button3 = new JButton("third button");
private JButton button4 = new JButton("fourth button");
public FlowLayoutDemo()
{
setSize(300, 300);
setLocation(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout());
// 添加按键,注意设置布局方式后任何对组件进行设置的方法,都会失效
add(this.button1);
add(this.button2);
add(this.button3);
add(this.button4);
}}
11.4.3:BorderLayout 布局管理器把容器分成五个局域:North,South,East,West和Center每个局域只能放一个组件.变化规律是:组件的相对位置不变,大小发生改变.
11.4.4:GridLayout 布局管理器将整个容器划分为n行m列的网格,平均占据容器的空间,按照组件加入的顺序优先考虑按行布局,当一行布局满之后再布局下一行每行只能布局m个组件.只有昂行列不满足指定的数值时,才按行进行扩展, 举例如下
public class GirdLayoutDemo extends JFrame
{
public static void main(String[] args)
{
GirdLayoutDemo gLayoutDemo = new GirdLayoutDemo();
gLayoutDemo.setVisible(true);
}
private JButton button1 = new JButton("first button");
private JButton button2 = new JButton("second button");
private JButton button3 = new JButton("third button");
private JButton button4 = new JButton("fourth button");
public GirdLayoutDemo()
{
setSize(300, 300);
setLocation(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 设置格式为两行两列
setLayout(new GridLayout(2, 2));
// 添加按键,注意设置布局方式后任何对组件进行设置的方法,都会失效
add(this.button1);
add(this.button2);
add(this.button3);
add(this.button4);
}}
11.4.5:复杂界面布局
为了实现该布局需要使用容器类,例如JPanel.JPanel是一种不可见的容器,其作用是对其他容器和组件进行组织.JPanel可以通过setLayout方法设置布局方式,也可以用add方法添加Swing组件或者其他容器.JPanel只有被布局在另外的容器上才可见.如果JPanel上没有任何Swing组件,则显示空白区域.除了JPanel,JScrollPane,和JTabbedPane也是Swing中常用的容器.JScrollPane是带有滚动条的容器,如果布局组件的大小超过了容器的大小,则可以显示水平和垂直方向的滚动条.JTabbedPane是用于产生选项卡界面的容器
public class ComplexLayout extends JFrame
{
public static void main(String[] args)
{
ComplexLayout complexLayout = new ComplexLayout();
complexLayout.setVisible(true);
}
private JPanel panel1 = new JPanel();
private JPanel panel2 = new JPanel();
private JPanel panel3 = new JPanel();
private JPanel panel4 = new JPanel();
// 构造方法
public ComplexLayout()
{
setSize(500, 500);
setLocation(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 对panel1进行布局
layoutPanel1();
// 对panel2进行布局
layoutPanel2();
// 对panel3进行布局
layoutPanel3();
// 对panel4进行布局
layoutPanel4();
// 对顶层容器进行布局,采用的GridLayout,2行列
setLayout(new GridLayout(2, 2));
add(this.panel1);
add(this.panel2);
add(this.panel3);
add(this.panel4);
}
// Panel1布局 格式为BorderLayout
private void layoutPanel1()
{
JButton north = new JButton("north");
JButton south = new JButton("south");
JButton east = new JButton("East");
JButton west = new JButton("west");
JButton center = new JButton("Center");
this.panel1.setLayout(new BorderLayout());
this.panel1.add(north, BorderLayout.NORTH);
this.panel1.add(south, BorderLayout.SOUTH);
this.panel1.add(west, BorderLayout.WEST);
this.panel1.add(east, BorderLayout.EAST);
this.panel1.add(center, BorderLayout.CENTER);
}
// Panel2布局 格式为FlowLayout
private void layoutPanel2()
{
JButton button1 = new JButton("First button");
JButton button2 = new JButton("Second button");
JButton button3 = new JButton("Third button");
JButton button4 = new JButton("Fourth button");
this.panel2.setLayout(new FlowLayout());
this.panel2.add(button1);
this.panel2.add(button2);
this.panel2.add(button3);
this.panel2.add(button4);
}
// Panel3布局 格式为GridLayout 两行两列
private void layoutPanel3()
{
JButton button1 = new JButton("First button");
JButton button2 = new JButton("Second button");
JButton button3 = new JButton("Third button");
JButton button4 = new JButton("Fourth button");
this.panel3.setLayout(new GridLayout(2, 2));
this.panel3.add(button1);
this.panel3.add(button2);
this.panel3.add(button3);
this.panel3.add(button4);
}
private void layoutPanel4()
{
JButton button = new JButton("JButton");
JTextField textField = new JTextField("JTextField");
this.panel4.setLayout(null);
this.panel4.setLocation(20, 20);
button.setSize(100, 20);
textField.setBounds(20, 50, 200, 100);
this.panel4.add(button);
this.panel4.add(textField);
}}
11.5 事件处理
11.5.1事件处理模型
GUI程序都需要对环境中的发生的各种事件(鼠标的单击,值的改变,焦点的获取或丢失,键盘输入等)进行监控并根据事件的类型进行相应的处理.Swing采用了委托事件模型,也叫授权模型,该模型主要包含三个对象
1事件:发生在用户界面的用户交互行为所产生的一种效果
2 事件源:产生事件的对象
3 事件监听器:接受事件并对其进行处理的对象
组件作为事件源可以触发事件,一个事件源注册一个或者多个事件监听器.
委托事件模型的优点:
1:事件对象只传给注册的监听器,不会意外的被其他组件或上层容器捕获和处理
2:可以实现过滤器的功能,只监听和处理感兴趣的事件
3:实现了将事件源和事件监听器分开处理的功能
public class EventDemo extends JFrame
{
public static void main(String[] args)
{
EventDemo eventDemo = new EventDemo();
eventDemo.setVisible(true);
}
JButton button = new JButton("press me");
public EventDemo()
{
setSize(300, 300);
setLocation(400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 设置默认事件,使用了匿名类
this.button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
// 获取被单击的按钮
JButton clickButton = (JButton) e.getSource();
clickButton.setText("I have been pressed");
}
});
setLayout(new BorderLayout());
add(this.button, BorderLayout.NORTH);
}}
11.5.2:事件类
事件既是基础,又是联系各个部分的桥梁.首先,组件作为事件源产生事件,不同类型的组件会产生不同的类型的事件.事件发生后,事件被传递给对应的事件监听器实现的事件的处理方法.基类是java.util.EventObject,基类定义了getSource方法,该方法返回产生或触发事件的对象.AWTEvent定义方法getID,该方法的返回值用来区别用同一个事件类所代表的不同类型的事件.
11.5.3:事件监听器
接收事件并对事件作出相应反应的对象称为事件监听器.一个类可以实现监听器的一个或多个接口,这就需要把所实现的接口中的所定义的方法都得到实现,当对其中的方法不感兴趣时,也可以将方法体保持为空,而不给出具体的方法
事件类别/接口名字 接口中的方法 产生事件的用户操作
ComponentEvent事件 Component Listenter 接口 |
Moved |
移动组件时 |
Hidden |
隐藏事件时 |
|
Resized |
改变组建大小 |
|
Shown |
显示组件时 |
|
ContainerEvent 事件及接口 |
Added |
添加组件时 |
Removed |
移动组件时 |
|
WindowEvent 窗口事件及接口 |
Opened |
打开窗户时 |
Activated |
激活窗口时 |
|
Dactived |
窗口失去焦点时 |
|
Closing |
关闭窗口时 |
|
Closed |
关闭窗口后 |
|
Iconified |
窗口最小化时 |
|
Deiconifed |
当窗口从最小化恢复到正常大小时 |
|
MouseEvent 鼠标事件和接口 |
Dragged |
鼠标拖动时 |
Moved |
鼠标移动时 |
|
Action 事件和接口 |
Performed |
单击按钮,在文本行中按回车键,双击列表框选择菜单项时 |
Text 文本事件和接口 |
textValueChanged |
文本行或文本区中修改内容 |
Mouse鼠标事件和接口 |
Clicked |
单击 |
Entered |
进入 |
|
Exited |
离开 |
|
Pressed |
按下 |
|
Released |
释放 |
|
KeyEvent键盘事件和接口 |
Pressed |
按下键盘时 |
Released |
释放键盘时 |
|
Typed |
敲击键盘时 |
|
Focus焦点事件和接口 |
Gained |
获得焦点时 |
Lost |
失去焦点时 |
11.5.4:事件适配器
每个有多个方法的监听器接口都对应于一个适配器
ComponentAdapter:组件适配器
ContainerAdapter :容器适配器
FocusAdapter 焦点适配器
KeyAdapter 键盘适配器
MouseAdapter 鼠标适配器
WindowAdapter 窗口适配器
使用适配器,只需要重写需要实现的方法,不用实现无关的方法,与监听器不同的是,监听器是一个接口,而适配器是个类
public class WindowclosingDemo extends JFrame
{
public static void main(String[] args)
{
WindowclosingDemo windowclosingDemo = new WindowclosingDemo();
windowclosingDemo.setVisible(true);
}
public WindowclosingDemo()
{
setSize(300, 300);
setLocation(400, 400);
// 设置默认关闭操作作为:什么都不做
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent e)
{
// 询问是否关闭窗口
int answer = JOptionPane.showConfirmDialog(null, "是否关闭窗口?",
"窗口信息", JOptionPane.YES_NO_CANCEL_OPTION);
if (answer == JOptionPane.YES_OPTION)
{
System.exit(0);
}
}
});}}