Swing 中提供了两种列表组件,分别为下拉列表框与列表框。下拉列表框与列表框都是带有一系列项目的组件,用户可以从中选择需要的项目。列表框较下拉列表框更直观,它将所有的项目罗列在列表框中;但下拉列表框较列表框更为便捷、美观,它将所有的项目隐藏起来,当用户选用其中的项目时才会显现出来。
1.1.1 JComboBox 类
下拉列表框是一个带条状的显示区,它具有下拉功能,在下拉列表框的右方存在一个倒三角形的按钮,当用户单击该按钮时,下拉 列表框中的项目将会以列表形式显示出来。
Swing 中的下拉列表框使用 JComboBox 类对象来表示,它是 javax.swing.JComponent 类的子类。它的常用构造方法如下 :
( 1 ) :public JComboBox() 。
( 2 ) :public JComboBox(ComboBoxModel dataModel) 。
( 3 ) :public JComboBox(Objet[] arrayDate) 。
( 4 ) :public JComboBox(Vector vector) 。
在初始化下拉列表框时,可以选择同时指定下拉列表框中的项目内容,也可以在程序中使用其他方法设置下拉列表框中的内容,下拉列表框中的内容可以被封装在 ComboBoxModel 类型、数组或 Vector 类型中。
1.1.2 JComboBox 模型
在开发过程中,一般将下拉列表框中的项目封装为 ComboBoxModel 的情况比较多。 ComboBoxModel 为接口,它代表一般模型,可以自定义一个类实现该接口,然后再初始化 JComboBox 对象时向上转型为 ComboBoxModel 接口类型,但是必须实现以下两种方法 :
( 1 ) :public void setSelectedIten(Object item) 。
( 2 ) :public Object getSelectedItem() 。
其中,setSelectedItem() 方法用于设置下拉列表框中的选中项, getSelectedItem() 方法用于返回下拉列表框中的选中项,有了这两个方法,就可以轻松地对下拉列表框中的项目进行操作。
自定义这个类除了实现该接口之外,还可以继承 AbstractListModel 类,在该类中也有两个操作下拉列表框的重要方法 :
( 1 ) : getSize() :返回列表的长度 。
( 2 ) : getElementAt(int index) :返回指定索引处的值 。
eg 1.1.2 在项目中创建 JComboBoxModelTest 类,使该类继承 JFrame 类称为窗体组件,在类中创建下拉列表框,并添加到窗体中。
package com.SwingDemo;
import java.awt.*;
import javax.swing.*;
public class JComboBoxModelTest extends JFrame {
private static final long serialVersionUID = 1L;
JComboBox jBox = new JComboBox<>(new MyComboBox());
JLabel jLabel = new JLabel("请选择证件:");
public JComboBoxModelTest() {
setSize(new Dimension(160, 180));
setVisible(true);
setTitle("在窗口中设置下拉列表框");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
Container container = getContentPane();
container.setLayout(new FlowLayout());
container.add(jBox);
container.add(jLabel);
}
public static void main(String[] args) {
new JComboBoxModelTest();
}
}
class MyComboBox extends AbstractListModel implements ComboBoxModel {
private static final long serialVersionUID = 1L;
String selectedItem = null;
String[] teStrings = { "身份证", "军人证", "学生证", "工作证" };
@Override
public String getElementAt(int index) { //根据索引返回值
return teStrings[index];
}
@Override
public int getSize() { //返回下拉列表框项目的数目
return teStrings.length;
}
@Override
public void setSelectedItem(Object anItem) { //设置下拉列表框项目
selectedItem = (String) selectedItem;
}
@Override
public Object getSelectedItem() { //获取下拉列表框项目
return selectedItem;
}
public int getIndex() {
for (int i = 0; i < teStrings.length; i++) {
if (teStrings[i].equals(getSelectedItem())) {
return i;
}
}
return 0;
}
}
运行结果为 :
自定义了一个实现 ComboBoxModel 接口并继承 AbstractListModel 类的类,这样这个类就可以实现或重写该接口与该类中的重要方法,同时在定义下拉列表框时,只要将该类向上转型为 ComboBoxModel 接口即可。
列表框(JList)与下拉列表框的区别不仅表现在外观上,当激活下拉列表框时,还会出现下拉列表框中的内容;但列表框只是在窗体上占据固定的大小,如果需要列表框具有滚动效果,可以将列表框放入滚动面板中。用户在选择列表框中的某一项时,按住 Shift 键并选择列表框中的其他项目,则当前选项和其他项目之间的选项将全部被选中;也可以按住 Ctrl 键并单击列表框中的单个项目,这样可以是列表框中被单击的项目反复切换非选择状态或选择状态。
Swing 中使用 JList 类对象来表示列表框,常用的构造方法 :
( 1 ) :public void JList() 。
( 2 ) :public void JList(Object[] listData) 。
( 3 ) :public void JList(Vector listData) 。
( 4 ) :public void JList(ListModel dataModel) 。
在上述构造方法中,存在一个没有参数的构造方法,可以通过在初始化列表框后使用 setListData() 方法对列表框进行设置,也可以在初始化的过程中对列表框中的项目进行设置。设置的方式有3 中类型,包括数组、Vector 类型和 ListModel 类型。
当使用数组作为构造方法的参数时,首先需要创建列表项目的数字,然后再利用构造方法来初始化列表框。
eg 1.2-1 使用数组作为初始化列表框的参数 。
String[] contents = {"列表 1","列表 2","列表 3","列表 4"};
JList jlist = new JList(contents);
eg 1.2-2 如果使用上述构造方法中的第 3 个构造方法,将 Vector 类型的数据作为初始化 JList 组件的参数。
Vector vector = new Vector();
JList jlist = new JList(vector);
vector.add("列表 1");
vector.add("列表 2");
vector.add("列表 3");
vector.add("列表 4");
如果使用 ListModel 模型为参数,需要创建 ListModel 对象。ListModel 是 Swing 包中的一个接口,它提供了获取列表框属性的方法。但是在通常情况下,为了使用户不完全实现 ListModel 接口中的方法,通常自定义一个类继承实现该接口的抽象类 AbstractListModel 。在这个类中提供了 getElementAt() 与 getSize() 方法,其中 getElementAt() 方法代表根据项目的索引获取列表框中的值,而 getSize() 方法用于获取列表框中的项目个数。
eg 1.2-3 在项目中创建 JListTest 类,是该类继承 JFrame 类成为窗体组件,在该类中创建列表框,并添加到窗体中。
package com.SwingDemo;
import java.awt.*;
import javax.swing.*;
public class JListTest extends JFrame {
private static final long serialVersionUID = 1L;
public JListTest() {
Container container = getContentPane();
container.setLayout(null);
JList jList = new JList<>(new MyListModel());
JScrollPane jScrollPane = new JScrollPane(jList);
jScrollPane.setBounds(10, 10, 100, 100);
container.add(jList);
setTitle("在这个窗体使用了列表框");
setVisible(true);
setSize(200, 150);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
}
public static void main(String[] args) {
new JListTest();
}
}
class MyListModel extends AbstractListModel { // 继承抽象类 AbstractListModel
private static final long serialVersionUID = 1L;
// 设置列表框内容
private String[] contents = { "列表 1", "列表 2", "列表 3", "列表 4", "列表 5", "列表 6" };
@Override
public String getElementAt(int index) { // 重写 getElementAt() 方法
if (index < contents.length) {
return contents[index++];
} else {
return null;
}
}
@Override
public int getSize() { // 重写 getSize() 方法
return contents.length;
}
}
运行结果为 :
还可以使用 DefaultListModel 类创建列表框,该类扩展了 AbstractListModel 类,所以也可以通过 DefaultListModel 对象向上转型为 ListModel 接口初始化列表框,同时 DefaultListModel 类提供了 dModel.addElement() 方法实现将内容添加至列表框中。
eg 1.2-4 使用 DefaultListModel 类创建列表框 。
final String[] flavors = { "列表1", "列表2", "列表3", "列表4", "列表5", "列表6" };
final DefaultListModel dModel = new DefaultListModel();
final JList jList = new JList<>(dModel); //实例化 JList 对象
for(int i=0;i<4;i++) {
dModel.addElement(flavors[i]); //为模型添加内容
}
文本组件在实际项目开发中使用最为广泛,尤其是文本框与密码框组件,通过文本组件可以很轻松地处理单行文字、多行文字、口令字段 。
文本框(JTextField)用来显示或编辑一个单行文本,在 Swing 中通过 javax.swing.JTextField 类对象创建,该类继承了 javax.swing.text.JTextComponent 类。
文本框常用的构造方法 :
( 1 ) :public JTextField() 。
( 2 ) :public JTextField(String text) 。
( 3 ) :public JTextField(int fieldwidth) 。
( 4 ) :public JTextField(String text , int fieldwidth) 。
( 5 ) :public JTextField(Document docModel , String text , int fieldWidth) 。
可以通过在初始化文本框时设置文本框的默认文字、文本框的长度等实现。
eg 2.1 在项目中创建 JTextFieldTest 类,使该类继承 JFrame 类成为窗体组件,在该类中创建文本框和按钮组件,并添加到窗体中。
package com.SwingDemo;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class JTextFieldTest extends JFrame {
private static final long serialVersionUID = 1L;
public JTextFieldTest() {
setSize(250, 100);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
Container container = getContentPane();
getContentPane().setLayout(new FlowLayout());
final JTextField jTextField = new JTextField("aaa", 20);
final JButton jButton = new JButton("清除");
container.add(jTextField);
container.add(jButton);
jTextField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
jTextField.setText("触发事件");
}
});
jButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
jTextField.setText("");
jTextField.requestFocus();
}
});
setVisible(true);
}
public static void main(String[] args) {
new JTextFieldTest();
}
}
运行结果为 :
在例子中主要设置了一个文本框和一个按钮,然后分别为文本框和按钮设置事件,当用户将光标焦点落于文本框中并按下 Enter 键时,文本框将执行 actionPerformed() 方法中设置的操作。同时还为按钮添加了相应的时间,当用户单击“清除”按钮时,文本框中的字符串将被清除 。
密码框(JPasswordField)与文本框的定义与用法基本相同,唯一不同的是密码框将用户输入的字符串以某种符号进行加密。密码框对象是通过 javax.swing.JPasswordField 类来创建的,JPasswordField 类的构造方法与 JTextField 类的构造方法非常相似。
( 1 ) :public JPasswordField() 。
( 2 ) :public JPasswordField(String text) 。
( 3 ) :public JPasswordField(int fieldwidth) 。
( 4 ) :public JPasswordField(String text , int fieldwidth) 。
( 5 ) :public JPasswordField(Document docModel , String text , int fieldWidth) 。
eg 2.2 定义密码框 。
JPasswordField jp = new JPasswordField();
jp.setEchoChar('#');//设置回显字符
在 JPasswordField 类中提供一个 setEchoChar() 方法,可以改变密码框的回显字符 。
Swing 中任何一个文本区域都是 JTextArea 类型的对象。JTextArea 常用的构造方法如下 :
( 1 ) :public JTextArea () 。
( 2 ) :public JTextArea (String text) 。
( 3 ) :public JTextArea (int rows , int columns) 。
( 4 ) :public JTextArea (Document doc) 。
( 5 ) :public JTextArea (Document doc, String text , int rows , int columns) 。
可以在初始化文本域时提供默认文本以及文本域的长与宽 。
eg 2.3 在项目中创建 JTextAreaTest 类,使该类继承 JFrame 类成为窗体组件,在该类中创建 JTextArea 组件的实例,并添加到窗体中 。
package com.SwingDemo;
import java.awt.*;
import javax.swing.*;
public class JTextAreaTest extends JFrame {
private static final long serialVersionUID = 1L;
public JTextAreaTest() {
setSize(200, 100);
setTitle("定义自动换行的文本域");
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
Container container = getContentPane();
JTextArea jArea = new JTextArea("文本域", 6, 6);
jArea.setLineWrap(true); // 可以自动换行
container.add(jArea);
setVisible(true);
}
public static void main(String[] args) {
new JTextAreaTest();
}
}
运行结果为 :
JTextArea 类中存在一个 setLineWrap() 方法,该方法用于设置文本域是否可以自动换行,如果将该方法的参数设置为 true ,文本域将自动换行,否则则不自动换行 。
之前所讲的组件本身并不带有任何功能。例如,在窗体中定义一个按钮,当用户单击该按钮时,虽然按钮可以凹凸显示,但在窗体中并没有实现任何功能。这是需要为按钮添加特定事件监听器,该监听器负责处理用户单击按钮后实现的功能。
在 Swing 事件模型中由 3 个分离的对象完成对事件的处理,分别为事件源、事件以及监听程序。事件源触发一个事件,它被一个或多个“监听器”接收,监听器负责处理事件。
所谓事件监听器,实质上就是一个“实现特定类型监听器接口”的类对象。具体地说,事件几乎都以对象来表示,它是某种事件类的对象,事件源(如按钮)会在用户作出相应的动作(如按钮被按下)时产生事件对象,如动作事件对应 ActionEvent 类对象,同时要编写一个监听器的类必须实现相应的接口,如 ActionEvent 类对应的是 ActionListener 接口,需要获取某个事件对象就必须实现相应的接口,同时需要将接口中的方法一一实现。最后事件源(按钮)调用相应的方法加载这个“实现特定类型监听器接口”的类对象,所有的事件源都具有 addXXXListener() 和 removeXXXListener() 方法(其中 XXX 方法表示监听事件类型),这样就可以为组件添加或移除相应的事件监听器 。
动作事件(ActionEvent)监听器是 Swing 中比较常用的事件监听器,很多组件的动作都会使用它监听,如按钮被单击。
事件名称 | 事件源 | 监听接口 | 添加或删除相应类型监听器的方法 |
ActionEvent | JButton 、 JList 、 JTextField 等 | ActionListenter | addActionListener() 、removeActionListener() |
eg 3.2 在项目中创建 SimpleEvent 类,使该类继承 JFrame 类成为窗体组件,在类中创建按钮组件,为按钮组件添加动作监听器,然后将按钮组件添加到窗体中。
package com.SwingDemo;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
public class SimpleEvent extends JFrame {
private static final long serialVersionUID = 1L;
private JButton jb = new JButton("我是按钮,单击我");
public SimpleEvent() {
setLayout(null);
setSize(200, 100);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
Container container = getContentPane();
container.add(jb);
jb.setBounds(10, 10, 100, 30);
jb.addActionListener(new jbAction());
setVisible(true);
}
class jbAction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
jb.setText("我被单击了");
}
}
public static void main(String[] args) {
new SimpleEvent();
}
}
运行结果为 :
在例子中,为按钮设置了动作监听器。由于获取时间监听时需要获取实现 ActionListener 接口的对象,所以定义了一个内部类 jbAction 实现 ActionListener 接口,同时在该内部类中实现了 actionPerformed() 方法,也就是在 actionPerformed() 方法中定义当用户单击该按钮后实现怎样的功能。
焦点事件(FocusEvent)监听器在实际项目开发中应用也比较广泛,如将光标焦点离开一个文本框时需要弹出一个对话框,或者将焦点返回给该文本框等。
事件名称 | 事件源 | 监听接口 | 添加或删除相应类型监听器的方法 |
FocusEvetn | Component 以及派生类 | FocusListener | addFocusListener() 、removeFocusListener() |
eg 3.3 在项目中创建 FocusEventTest 类,使该类继承 JFrame 类成为窗体组件,在类中创建文本框组件,并为文本框添加焦点事件监听器,将文本框组件添加到窗体中。
package com.SwingDemo;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
public class FocusEventTest extends JFrame {
private static final long serialVersionUID = 1L;
public FocusEventTest() {
setSize(250, 100);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
Container container = getContentPane();
container.setLayout(new FlowLayout());
final JLabel jLabel = new JLabel();
container.add(jLabel);
JTextField jTextField1 = new JTextField("请单击其他文本框", 10);
JTextField jTextField2 = new JTextField("请单击我", 10);
container.add(jTextField1);
container.add(jTextField2);
jTextField1.addFocusListener(new FocusListener() {
// 组件失去焦点时调用的方法
@Override
public void focusLost(FocusEvent e) {
JOptionPane.showMessageDialog(null, "文本框失去焦点");
}
// 组件获取键盘焦点时调用的方法
@Override
public void focusGained(FocusEvent e) {
}
});
setVisible(true);
}
public static void main(String[] args) {
new FocusEventTest();
}
}
运行结果为 :
在例子中,为文本框组件添加了焦点事件监听器。这个监听器需要实现 FocusListener 接口。在该接口中定义了两个方法,分别为 focusLost() 与 focusGained() 方法,其中 focusLost() 方法是在组件失去焦点时调用的,而 focusGained() 方法是在组件获取焦点调用的。本例需要实现在文本框失去焦点时弹出相应对话框的功能,所以重写 focusLost() 方法,同时在为文本框添加监听时使用了匿名内部类的形式,将实现 FocusListener 接口对象传递给 addFocusListener() 方法。