目录
图形用户界面基础
JFrame的作用
JFrame是Swing创建视窗的一个基础类,它像一个容器一样,可以包含其他的组件进来,是其他组件赖以生存的对象。
JFrame的使用
JFrame的使用比较简单,主要有以下几个步骤:
1)用new语句创建JFrame对象,可以通过构造方法传入视窗标题参数。
2)设置窗口关闭时的行为,一般是结束进程。
3)设置视窗的外观,例如,尺寸、可见与否等。
4)为窗口中添加其他的组件,例如,标签、按钮等。
public class HelloJFrame {
public static void main(String[] args) {
//创建JFrame对象
JFrame jf = new JFrame("hello swing");
//设置窗口关闭时,程序的响应(默认情况下,视窗关闭不会结束程序)
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口大小
jf.setSize(200, 200);
//是否可见
jf.setVisible(true);
//为窗口添加一个标签
//创建JLable对象
JLabel label = new JLabel();
//设置标签文本
label.setText("Hello this is one label");
//把标签添加到jframe
jf.add(label);
}
}
注意:
- 以上代码setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)方法必须要调用的,否则默认情况下,视窗关闭时是不会结束程序的。
- Swing的大多数组件类的类名都是以J字母开头,主要是为了与AWT的老组件相区别。
创建JButton按钮
public class HelloJButton {
public static void main(String[] args) {
//创建JFrame对象
JFrame jf = new JFrame("hello swing");
//设置窗口在关闭时,程序响应
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口大小
jf.setSize(200, 200);
//是否可见
jf.setVisible(true);
//设置布局样式
jf.setLayout(new FlowLayout());
//为窗口添加一个按钮
JButton btn = new JButton("my button");
jf.add(btn);
}
}
注意:
- 如果没有设置布局格式,JFrame是无法直接加入JButton组件的,即使调用了add()方法,界面上也是空白的。
使用文本输入组件
Swing提供两种文本输入组件,一个是JTextField,它代表只能单行输入的文本框,另一个是JTextArea,它代表可以多行输入。它们的使用方式类似,都是通过在容器中添加组件即可。
JTextField组件在创建对象的时候,一般需要提供长度参数。JTextArea组件的创建过程则提供的是长度和高度两个参数。
public class HelloJText {
public static void main(String[] args) {
//创建JFrame对象
JFrame jf = new JFrame("Hello Text");
//设置布局格式
jf.setLayout(new FlowLayout());
//创建一个文本框对象
JTextField jtf = new JTextField(10);
//设置文本初始内容
jtf.setText("初始化内容");
//创建一个5行10列的文本域对象
JTextArea jta = new JTextArea(5, 10);
//设置初始化文本内容
jta.setText("初始化内容\n...");
//加到窗口中
jf.add(jtf);
jf.add(jta);
showMe(jf);
}
private static void showMe(JFrame jf){
//设置窗口在关闭时,程序的响应
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口大小
jf.setSize(400, 400);
//是否可见
jf.setVisible(true);
}
}
捕获事件
在Swing程序中,通过注册监听的方式来捕获事件。也就是说,组件可以根据需要来添加监听器进行某些事件的监听,其他事件不予理睬。Swing的事件模型编程思路有以下几项。
- 创建组件对象,如JButton。
- 创建实现了监听器接口或继承自适配器类的实现类,实现需要进行相应动作的抽象方法。
- 调用组件对象的addXXXListener()方法,为该组件添加某监听器。
public class HelloEvent {
//创建一个文本框对象
private static JTextField text = new JTextField(10);
public static void main(String[] args) {
//创建JFrame对象
JFrame jf = new JFrame("Hello Text");
//设置布局格式
jf.setLayout(new FlowLayout());
//为窗口添加一个文本框
jf.add(text);
//为窗口添加一个按钮
JButton btn = new JButton("my button");
jf.add(btn);
//添加事件
btn.addActionListener(new ActionListener() {
@Override
//定义事件回调方法
public void actionPerformed(ActionEvent e) {
HelloEvent.text.setText("按钮被点击了");
}
});
showMe(jf);
}
private static void showMe(JFrame jf){
//设置窗口在关闭时,程序的响应
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口大小
jf.setSize(400, 400);
//是否可见
jf.setVisible(true);
}
}
布局控制
BorderLayout布局
BorderLayout是Swing容器的默认布局管理器,它的含义是采用东西南北中5个方位来进行布局,可以分别往这些方位上放置组件。在编程时,使用容器的add()方法即可,第一个参数为需要添加的组件,第二个参数则是布局的方位。
注意:
- 如果通过只有一个参数的add()方法添加组件,容器会默认地把组件放在中间位置。
变量 | 说明 |
---|---|
BorderLayout.NORTH | 上端 |
BorderLayout.SOUTH | 下端 |
BorderLayout.EAST | 右端 |
BorderLayout.WEST | 左端 |
BorderLayout.CENTER | 中部 |
public class HelloBorderLayout {
public static void main(String[] args) {
//创建JFrame对象
JFrame jf = new JFrame("BorderLayout test");
//设置布局方式
jf.setLayout(new BorderLayout());
jf.add(new JButton("east"), BorderLayout.EAST);
jf.add(new JButton("center"), BorderLayout.CENTER);
jf.add(new JButton("south"), BorderLayout.SOUTH);
jf.add(new JButton("north"), BorderLayout.NORTH);
jf.add(new JButton("west"), BorderLayout.WEST);
jf.setSize(400, 400);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
FlowLayout布局
FlowLayout布局器采用一种流线型的布局方式,把组件从左到右依次地放置,如果摆放不下,则换到下一行继续摆放。
当某种容器需要使用该布局管理器时,只需要调用setLayout()方法,传入一个FlowLayout对象即可。在加入组件的时候,直接调用add()方法,不需要指定其他参数。
public class HelloFlowLayout {
public static void main(String[] args) {
JFrame jf = new JFrame("Hello FlowLayout");
jf.setLayout(new FlowLayout());
for (int i = 0; i < 10; i++) {
jf.add(new JButton(i + ""));
}
jf.setSize(640, 200);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
注意:
如果窗口的大小发生变化,就会影响到FlowLayout的排列方式。例如,本来是一排,就可能变成多排。
GridLayout布局
GridLayout布局管理器采用的是一种表格式的布局方式,它把容器等分为N*N个格子,然后把加入的组件依次放置在格子中。
当某种容器需要使用该布局管理器时,只需要调用setLayout()方法,传入一个GridLayout对象即可,只不过GridLayout对象在创建的时候,需要指定它的行数和列数,在加入组件时,直接调用add()方法,不需要指定其他的参数。
public class HelloGridLayout {
public static void main(String[] args) {
JFrame jf = new JFrame("GridLayout test");
//创建GridLayout,10行10列
GridLayout grid = new GridLayout(10, 10);
//设置Grid
jf.setLayout(grid);
for (int i = 0; i < 100; i++) {
jf.add(new JButton(i + ""));
}
jf.setSize(640, 480);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
注意:
当窗口变大的时候,每个格子的面积也会增大,按钮也会随着变大。
事件模型
通用规则
Swing的事件类型比较多,但它们都有一个通用的使用和定义规则,主要有以下几点。
- 组件都有addXXXListener()和removeXXXListener()方法,XXX就代表了事件的类型和含义。
- XXX事件的监听器类型叫做XXXListener。
- XXX事件的类名叫做XXXEvent,它往往作为XXXListener接口方法中的参数类型。
监听器、事件 | 添加和取消方法 | 支持该事件的常见组件 |
---|---|---|
ActionEvent ActionListener | addActionListener() removeActionListener() | JButton、JList、JMenu、JMenuItem |
KeyEvent KeyListener | addKeyListener() removeKeyListener() | 几乎所有的组件 |
MouseEvent MouseListener | addMouseListener() removeMouseListener() | 几乎所有的组件 |
WindowEvent WindowListener | addWindowListener() removeWindowListener() | Window及其子类,JDialog、JFrame |
TextEvent TextListener | addTextListener() removeTextListener() | 文本输入组件,JTextField、JTextArea |
监听器&适配器
在Java开发领域,有一种开发模式叫做适配器开发模式,Swing的适配器正是采用这种模式开发的。为了避免代码冗余,Swing监听器的适配器就是为一些监听器接口的方法提供默认的空实现,这样开发者可以直接继承自适配器就好,不必把每一个接口方法都实现。也可以根据需要自定义一些适配器。
大家知道为一个组件添加事件监听器就是加入一个监听器接口的类实例,调用addXXXListener()方法即可。但是如果这个接口方法太多,而开发中只使用其中的一些,这岂不是浪费,有接口侵入之嫌。
public class HelloKeyEvent {
public static void main(String[] args) {
JFrame jf = new JFrame("hello event");
jf.setLayout(new FlowLayout());
JTextField jtf = new JTextField(15);
jf.add(jtf);
//添加监听器
jtf.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
//空实现
}
@Override
public void keyPressed(KeyEvent e) {
System.out.println(e.getKeyChar()+" pressed");
}
@Override
public void keyReleased(KeyEvent e) {
//空实现
}
});
showMe(jf);
}
private static void showMe(JFrame jf){
//设置窗口在关闭时,程序的响应
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口大小
jf.setSize(400, 400);
//是否可见
jf.setVisible(true);
}
}
那么有没有一个类提供这些接口的基本实现呢?
这就是适配器。
public class HelloKeyEvent2 {
public static void main(String[] args) {
JFrame jf = new JFrame("hello event");
jf.setLayout(new FlowLayout());
JTextField jtf = new JTextField(15);
jf.add(jtf);
//添加监听器
jtf.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
System.out.println(e.getKeyChar()+" pressed");
}
});
showMe(jf);
}
private static void showMe(JFrame jf){
//设置窗口在关闭时,程序的响应
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口大小
jf.setSize(400, 400);
//是否可见
jf.setVisible(true);
}
}
效果与上图相同。
注意:
适配器是一个类,如果事件处理类已经继承自其他接口的话,就不能继承自适配器类了。另外,开发者也可以自己写一个适配器,为一些事件方法提供一些自定义的初始化实现。例如,每次事件的触发就记录一次日志。