第十三章 运用Swing
1. swing的组件
组件(component,或称元件)是比我们之前所称的widget更为正确的术语。它们就是你放在GUI上的东西。这些东西是用户会看到并与其交互的,像是Text Field、 button、 scrollable list、radio button等。事实上所有的组件都是继承自javax.swing.JComponent。
组件是可以进行嵌套的。你可以把任何东西放在其他东西上,就像把按钮或是列表等用户交互组件放在框架和面板等背景组件上。
2. 布局管理器(Layout Managers)
布局管理器是个与特定组件相关的Java对象,它大多数是背景组件。布局管理器用来控制所关联组件上携带的其他组件。举个例子,如果某个框架带有面板,面板上带有按钮,则面板的布局管理器控制着按钮的大小和位置,框架的布局管理器则控制着面板的大小和位置。按钮因为没有携带其他组件,所以不需要布局管理器。
三大首席管理器border、flow和box
1. BorderLayout
这个管理器会把背景组件分割成五个区域。每个被管理的区域只能放一个组件。由此管理员安置的组件通常不会取得默认的大小。这是框架(JFrame)默认的布局管理器。
BorderLayout管理器我们在上一节中经常使用,它的策略就是当按钮在南北区域时,宽度会恒等于面板宽度,而高度由字体大小调节。而进驻东西区域时,高度恒等于面板高度,宽度根据文字数决定,文字数越多,其按钮越宽。中间区域只能捡剩下的,把四方安置完毕后,BorderLayout才会去管中间部分(特殊情况稍微介绍)
2. FlowLayout
这个管理器的行为和文书处理程序的版面配置方法差不多。每个组件都会依照理想的大小呈现,并且会从左到右依照加入的顺序以可能会换行的方式排列。因此在组件放不下时会被放到下一行。这是面板(JPanel)默认的布局管理器。
import javax.swing.*;
import java.awt.*;
public class Panel1 {
public static void main(String[] args) {
Panel1 gui = new Panel1();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setBackground(Color.drakGrey); // 让面板变为灰色的
JButton button = new JButton("shock me");
panel.add(button); // 把按钮加到面板上面,面板会根据按钮大小调节宽度
frame.getContentPane().add(BorderLayout.EAST, panel);
frame.setSize(250, 500);
frame.setVisible(true);
}
}
在放入两个按钮后它会变得并排放置,变得更加糟糕···
3. BoxLayout
它就像FlowLayout一样让每个组件使用默认的大小,并且按照加入的顺序来排列。但BoxLayout是以垂直的方式来排列(也可以水平,但通常我们只在乎垂直方式)。不像FlowLayout会自动换行,它让你插入某种类似换行的机制来强制组件从新的一行开始。
BoxLayout布局是救星,就算水平宽度足够容纳组件,它还是会用新的行来排列组件。下面是把面板的布局管理器从默认的FlowLayout布局改成BoxLayout布局
public void go() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setBackground(Color.darkGrey);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); // 把布局管理器更换,它的构造函数需要知道要管理哪个组件以及使用哪个轴
...
}
布局管理器要点
- 布局管理器会控制嵌套在其他组件中组件的大小和位置
- 当某个组件加到背景组件上面时,被加入的组件是由背景组件的布局管理器控制的
- 布局管理器在做决定之前会询问组件的理想大小,并根据策略来决定采用哪些数据
- BorderLayout布局可以让你把组件加到五个区域上
- BorderLayout布局上的南北区域使用组件的理想高度而不管宽度,东西区域刚好相反,中间区域只能使用剩下来的空间
- pack()方法会使Windows大小符合内含组件的大小
- FlowLayout布局会从左至右、由上至下依次加入的顺序来安置组件,若宽度超过时就会换行
- FlowLayout布局会让组件在长宽上都是用理想的尺寸大小
- BoxLayout布局让你可以垂直地排列组件,如同FlowLayout布局一样,它让组件在长宽是都是用理想的尺寸大小
- 框架默认时是用BorderLayout布局,面板默认是用FlowLayout布局
- 可以调用setLayout()来改变面板的布局管理器
3. 操作swing组件
1. JTextField
JTextField可以开启接收一行文字的单个窗口,示例如下:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Test2 implements ActionListener {
JTextField field;
JFrame frame;
JPanel panel;
public static void main(String[] args) {
Test2 gui = new Test2();
gui.go();
}
public void go() {
frame = new JFrame("test window");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Enter your name:"); // 建立标签
panel = new JPanel();
frame.getContentPane().add(BorderLayout.NORTH, panel); // 填加面板至北方
field = new JTextField(20); // 建立可容纳20字宽的JTextField
JButton button = new JButton("submit"); //建立接收按钮
button.addActionListener(this);
panel.add(label); // 面板填加组件
panel.add(field);
panel.add(button);
frame.setSize(500, 500);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
System.out.println("Client's name is " + field.getText()); // 按钮功能
field.setText(""); // 清空文本框内内容
}
}
输出为:
>>> Client's name is Charles095
同时JTextField也能够直接接上接口,通过用户输入完毕后按下enter或者return键时注册事件。
field.addActionListener(MyActionListener);
2. JTextArea
JTextArea可以有超过一行文字,它还可以通过填加ScrollPane进行文本区域的滚动。
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Test2 implements ActionListener {
JTextArea text;
public static void main(String[] args) {
Test2 gui = new Test2();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
JButton button = new JButton("Just Click It");
button.addActionListener(this);
text = new JTextArea(10, 20); // 10,20分别代表行高和字宽
text.setLineWrap(true); // 启动自动换行
JScrollPane scroller = new JScrollPane(text); // 将text赋值给新创建的JScrollPane
// 指定只是用垂直滚动条,关闭水平滚动条
scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
panel.add(scroller); // 加入的是带有文本域的滚动条而不是文本域
frame.getContentPane().add(BorderLayout.CENTER, panel);
frame.getContentPane().add(BorderLayout.SOUTH, button);
frame.setSize(350, 300);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
text.append("button clicked \n"); // append让文本加上该内容,加入“\n”可以分行
}
}
3. JCheckBox
JCheckBox可以生成可勾选的组件
// 构造函数
JCheckBox check = new JCheckBox("Add Milk");
//监听item的事件(被选取或变成非选取)
check.addItemListener(this);
// 处理事件(判别是否被选取)
public void itemStateChanged(ItemEvent ev) {
String onOrOff = 'off';
if (check.isSelected()) onOrOff = 'on';
System.out.println("Check box is " + onOrOff);
}
// 用程序来选取或不选取
check.setSelected(true);
check.setSelected(false);
4. JList
JLIst能够生成一个可滚动的选单条
// 构造函数
String [] listEntries = {"apple", "banana", "orange", "pear","watermelon","peach","strawberry"};
list = new JList(listEntries);
// 显示垂直滚动条,方法和JTextArea一样,使用JScrollPane实现
JScrollPane scroller = new JScrollPane(list);
scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
panel.add(scroller);
// 设定显示的行数
list.setVisibleRowCount(4);
// 限制用户只能选取一个项目
list.setSelectionMode(ListSelectionModel.SINCLE_SELECTION);
// 对选择事件做注册
list.addListSelectionListener(this);
// 处理事件(判断选了哪个项目)
public void valueChanged(ListSelectionEvent lse) {
if( !lse.getValueIsAdjusting()) {
String selection = (String) list.getSelectedValue();
System.put.println(selection);
}
}