Swing 基本组件 II
最后修改于 2023 年 1 月 10 日
在本 Java Swing 教程的这一章中,我们将继续介绍 Java Swing 组件。
我们提到了以下组件:JCheckBox, JRadioButton, JSlider, JComboBox, JProgressBar, JToggleButton, JList, JTabbedPane, JTextArea 和 JTextPane。
JCheckBox
JCheckBox 是一个带有标签的复选框,它有两个状态:选中和未选中。 如果选中复选框,则它在框中显示一个勾号。 复选框可用于在启动时显示或隐藏启动画面,切换工具栏的可见性等。
使用 JCheckBox,可以使用 ActionListener 或 ItemListener。 通常使用后一个选项。 ItemListener 是用于接收项目事件的接口。 对处理项目事件(例如观察者)感兴趣的类实现此接口。 观察者对象使用组件的 addItemListener() 方法在组件中注册。 当发生项目选择事件时,将调用观察者的 itemStateChanged() 方法。
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.awt.EventQueue;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
public class CheckBoxEx extends JFrame
implements ItemListener {
public CheckBoxEx() {
initUI();
}
private void initUI() {
var cb = new JCheckBox("Show title", true);
cb.addItemListener(this);
createLayout(cb);
setSize(280, 200);
setTitle("JCheckBox");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
public void itemStateChanged(ItemEvent e) {
int sel = e.getStateChange();
if (sel == ItemEvent.SELECTED) {
setTitle("JCheckBox");
} else {
setTitle("");
}
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setHorizontalGroup(gl.createParallelGroup()
.addComponent(arg[0])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new CheckBoxEx();
ex.setVisible(true);
});
}
}
我们的代码示例显示或隐藏窗口的标题,具体取决于是否选中复选框。
public class CheckBoxEx extends JFrame
implements ItemListener {
我们的应用程序类实现了 ItemListener。 这意味着此类必须提供 itemStateChanged() 方法,在该方法中我们对项目选择事件做出反应。
var checkbox = new JCheckBox("Show title", true);
创建 JCheckBox。 此构造函数将文本和复选框的状态作为参数。 初始情况下,复选框被选中。
cb.addItemListener(this);
应用程序类注册为复选框选择事件的观察者。
@Override
public void itemStateChanged(ItemEvent e) {
int sel = e.getStateChange();
if (sel == ItemEvent.SELECTED) {
setTitle("JCheckBox");
} else {
setTitle("");
}
}
我们调用 ItemEvent 的 getStateChange() 方法来确定复选框的状态。 ItemEvent 是一个语义事件,指示项目被选中或取消选中。 它被发送给注册的观察者。 根据复选框的状态,我们使用 setTitle() 方法显示或隐藏窗口的标题。
注意复选框文本周围的蓝色矩形。 它表明此组件具有键盘焦点。 可以使用 Space 键选择和取消选择复选框。
JRadioButton
JRadioButton 允许用户从一组选项中选择单个独占选项。 它与 ButtonGroup 组件一起使用。
package com.zetcode;
import javax.swing.ButtonGroup;
import javax.swing.GroupLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.LayoutStyle;
import java.awt.EventQueue;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import static javax.swing.LayoutStyle.ComponentPlacement.RELATED;
public class RadioButtonEx extends JFrame
implements ItemListener {
private JLabel sbar;
public RadioButtonEx() {
initUI();
}
private void initUI() {
var lbl = new JLabel("Difficulty");
var group = new ButtonGroup();
var rb1 = new JRadioButton("Easy", true);
var rb2 = new JRadioButton("Medium");
var rb3 = new JRadioButton("Hard");
group.add(rb1);
group.add(rb2);
group.add(rb3);
sbar = new JLabel("Selected: Easy");
rb1.addItemListener(this);
rb2.addItemListener(this);
rb3.addItemListener(this);
createLayout(lbl, rb1, rb2, rb3, sbar);
setSize(350, 250);
setTitle("Radio buttons");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
@Override
public void itemStateChanged(ItemEvent e) {
int sel = e.getStateChange();
if (sel == ItemEvent.SELECTED) {
var button = (JRadioButton) e.getSource();
var text = button.getText();
var sb = new StringBuilder("Selected: ");
sb.append(text);
sbar.setText(sb.toString());
}
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setHorizontalGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addComponent(arg[1])
.addComponent(arg[2])
.addComponent(arg[3])
.addComponent(arg[4])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(arg[1])
.addComponent(arg[2])
.addComponent(arg[3])
.addPreferredGap(RELATED,
GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(arg[4])
);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new RadioButtonEx();
ex.setVisible(true);
});
}
}
该示例有三个单选按钮; 选中的单选按钮的值显示在状态栏中。
var group = new ButtonGroup();
var rb1 = new JRadioButton("Easy", true);
var rb2 = new JRadioButton("Medium");
var rb3 = new JRadioButton("Hard");
group.add(rb1);
group.add(rb2);
group.add(rb3);
创建了三个 JRadioButtons,并将它们放入 ButtonGroup 中。 第一个单选按钮被预先选中。
rb1.addItemListener(this); rb2.addItemListener(this); rb3.addItemListener(this);
所有三个单选按钮共享一个 ItemListener。
if (sel == ItemEvent.SELECTED) {
当我们选择一个单选按钮时,实际上会触发两个事件:一个用于选择,一个用于取消选择。 我们对选择感兴趣。
var button = (JRadioButton) e.getSource(); var text = button.getText();
我们使用 getSource() 方法获取事件的源,并获取单选按钮的文本标签。
var sb = new StringBuilder("Selected: ");
sb.append(text);
sbar.setText(sb.toString());
我们构建字符串并将其设置为标签。
JSlider
JSlider 是一个组件,允许用户通过在有界间隔内滑动旋钮来以图形方式选择一个值。 移动滑块的旋钮时,将调用滑块的 ChangeListener 的 stateChanged() 方法。
刻度线
JSlider 可以选择显示其值的范围的刻度线。 刻度线由 setMinorTickSpacing()、setMajorTickSpacing() 和 setPaintTicks() 方法控制。
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import java.awt.EventQueue;
public class SliderEx extends JFrame {
private JSlider slider;
private JLabel lbl;
public SliderEx() {
initUI();
}
private void initUI() {
slider = new JSlider(0, 100, 0);
slider.setMinorTickSpacing(5);
slider.setMajorTickSpacing(10);
slider.setPaintTicks(true);
slider.addChangeListener((ChangeEvent event) -> {
int value = slider.getValue();
lbl.setText(Integer.toString(value));
});
lbl = new JLabel("...");
createLayout(slider, lbl);
setTitle("JSlider");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addComponent(arg[1])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addComponent(arg[1])
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new SliderEx();
ex.setVisible(true);
});
}
}
在代码示例中,从滑块中选择的值显示在标签组件中。
slider = new JSlider(0, 100, 0);
使用最小、最大和当前值作为参数创建一个 JSlider。
slider.setMinorTickSpacing(5); slider.setMajorTickSpacing(10);
我们设置次要和主要刻度线之间的距离。
slider.setPaintTicks(true);
setPaintTicks() 方法确定是否在滑块上绘制刻度线。
slider.addChangeListener((ChangeEvent event) -> {
int value = slider.getValue();
lbl.setText(Integer.toString(value));
});
当滑块以某种方式更改时,将触发 ChangeEvent。 我们使用滑块的 getValue() 方法获取滑块的当前值,使用 Integer.toString() 将整数转换为字符串,并使用标签的 setText() 方法将其设置为标签。
音量控制
第二个示例使用 JSlider 创建一个音量控制。
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import java.awt.EventQueue;
public class SliderEx2 extends JFrame {
private JSlider slider;
private JLabel lbl;
private ImageIcon mute;
private ImageIcon min;
private ImageIcon med;
private ImageIcon max;
public SliderEx2() {
initUI();
}
private void initUI() {
loadImages();
slider = new JSlider(0, 150, 0);
slider.addChangeListener((ChangeEvent event) -> {
int value = slider.getValue();
if (value == 0) {
lbl.setIcon(mute);
} else if (value > 0 && value <= 30) {
lbl.setIcon(min);
} else if (value > 30 && value < 80) {
lbl.setIcon(med);
} else {
lbl.setIcon(max);
}
});
lbl = new JLabel(mute, JLabel.CENTER);
createLayout(slider, lbl);
setTitle("JSlider");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void loadImages() {
mute = new ImageIcon("src/resources/mute.png");
min = new ImageIcon("src/resources/min.png");
med = new ImageIcon("src/resources/med.png");
max = new ImageIcon("src/resources/max.png");
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addComponent(arg[1])
);
gl.setVerticalGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addComponent(arg[1])
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new SliderEx2();
ex.setVisible(true);
});
}
}
在代码示例中,我们显示一个 JSlider 和一个 JLabel 组件。 通过拖动滑块,我们更改标签组件上的图标。
slider = new JSlider(0, 150, 0);
这是一个 JSlider 构造函数。 参数是最小值、最大值和当前值。
private void loadImages() {
mute = new ImageIcon("src/resources/mute.png");
min = new ImageIcon("src/resources/min.png");
med = new ImageIcon("src/resources/med.png");
max = new ImageIcon("src/resources/max.png");
}
在 loadImages() 方法中,我们从磁盘加载图像文件。
slider.addChangeListener((ChangeEvent event) -> {
...
});
我们向滑块添加一个 ChangeListener。 在侦听器内部,我们确定当前的滑块值并相应地更新标签。
JComboBox
JComboBox 是一个组件,它结合了一个按钮或可编辑字段和一个下拉列表。 用户可以从下拉列表中选择一个值,该列表会在用户请求时出现。 如果您使组合框可编辑,则组合框包括一个可编辑字段,用户可以在其中键入一个值。
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.EventQueue;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import static javax.swing.GroupLayout.Alignment.BASELINE;
public class ComboBoxEx extends JFrame
implements ItemListener {
private JLabel display;
private JComboBox<String> box;
private String[] distros;
public ComboBoxEx() {
initUI();
}
private void initUI() {
distros = new String[]{"Ubuntu", "Redhat", "Arch",
"Debian", "Mint"};
box = new JComboBox<>(distros);
box.addItemListener(this);
display = new JLabel("Ubuntu");
createLayout(box, display);
setTitle("JComboBox");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addComponent(arg[1])
);
gl.setVerticalGroup(gl.createParallelGroup(BASELINE)
.addComponent(arg[0])
.addComponent(arg[1])
);
pack();
}
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
display.setText(e.getItem().toString());
}
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new ComboBoxEx();
ex.setVisible(true);
});
}
}
在我们的示例中,我们有一个组合框和一个标签。 组合框包含一个字符串列表,表示 Linux 发行版的名称。 从组合框中选择的项显示在标签中。 组合框使用其 ItemListener 来检测更改。
distros = new String[] {"Ubuntu", "Redhat", "Arch",
"Debian", "Mint"};
JComboBox 将保存这些字符串值。
display = new JLabel("Ubuntu");
显示区域是一个简单的 JLabel。 它显示最初在组合框中显示的项。
box = new JComboBox<>(distros); box.addItemListener(this);
JComboBox 的构造函数采用一个 Linux 发行版的字符串数组。 我们将一个侦听器插入到创建的对象中。
gl.setVerticalGroup(gl.createParallelGroup(BASELINE)
.addComponent(arg[0])
.addComponent(arg[1])
);
在垂直方向上,这两个组件将与它们的文本的基线对齐。
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
display.setText(e.getItem().toString());
}
}
当用户选择或取消选择一个项目时,会调用 itemStateChanged()。 我们检查 ItemEvent.SELECTED 状态,并将组合框的选定项目设置为标签。
JProgressBar
进度条是在我们处理冗长任务时使用的组件。 它是动画的,以便用户知道我们的任务正在进行中。 JProgressBar 组件提供水平或垂直进度条。 初始值和最小值均为 0,最大值为 100。
package com.zetcode;
import javax.swing.AbstractAction;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.Timer;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import static javax.swing.GroupLayout.Alignment.CENTER;
public class ProgressBarEx extends JFrame {
private Timer timer;
private JProgressBar progBar;
private JButton startBtn;
private final int MAX_VAL = 100;
public ProgressBarEx() {
initUI();
}
private void initUI() {
progBar = new JProgressBar();
progBar.setStringPainted(true);
startBtn = new JButton("Start");
startBtn.addActionListener(new ClickAction());
timer = new Timer(50, new UpdateBarListener());
createLayout(progBar, startBtn);
setTitle("JProgressBar");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addComponent(arg[1])
);
gl.setVerticalGroup(gl.createParallelGroup(CENTER)
.addComponent(arg[0])
.addComponent(arg[1])
);
pack();
}
private class UpdateBarListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
int val = progBar.getValue();
if (val >= MAX_VAL) {
timer.stop();
startBtn.setText("End");
return;
}
progBar.setValue(++val);
}
}
private class ClickAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
if (timer.isRunning()) {
timer.stop();
startBtn.setText("Start");
} else if (!"End".equals(startBtn.getText())) {
timer.start();
startBtn.setText("Stop");
}
}
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new ProgressBarEx();
ex.setVisible(true);
});
}
}
该示例显示一个进度条和一个按钮。 该按钮启动和停止进度。
progBar = new JProgressBar(); progBar.setStringPainted(true);
在这里,我们创建 JProgressBar 组件。 最小值为 0,最大值为 100,初始值为 0。这些是默认值。 setStringPainted() 方法确定进度条是否显示任务完成的百分比。
timer = new Timer(50, new UpdateBarListener());
计时器对象每 50 毫秒启动 UpdateBarListener。 在侦听器内部,我们检查进度条是否达到其最大值。
private class UpdateBarListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
int val = progBar.getValue();
if (val >= MAX_VAL) {
timer.stop();
startBtn.setText("End");
return;
}
progBar.setValue(++val);
}
}
侦听器的 actionPerformed() 方法增加进度条的当前值。 如果它达到最大值,则停止计时器,并将按钮的标签设置为“End”。
private class ClickAction extends AbstractAction {
@Override
public void actionPerformed(ActionEvent e) {
if (timer.isRunning()) {
timer.stop();
startBtn.setText("Start");
} else if (!"End".equals(startBtn.getText())) {
timer.start();
startBtn.setText("Stop");
}
}
}
按钮启动或停止计时器。 按钮的文本被动态更新; 它可以具有“Start”、“Stop”或“End”字符串值。
JToggleButton
JToggleButton 是一个有两个状态的按钮:按下和未按下。 我们通过单击它在这两个状态之间切换。 在某些情况下,此功能非常适合。
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.border.LineBorder;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import static javax.swing.GroupLayout.Alignment.CENTER;
import static javax.swing.LayoutStyle.ComponentPlacement.UNRELATED;
public class ToggleButtonEx extends JFrame
implements ActionListener {
private JToggleButton redBtn;
private JToggleButton greenBtn;
private JToggleButton blueBtn;
private JPanel display;
public ToggleButtonEx() {
initUI();
}
private void initUI() {
redBtn = new JToggleButton("red");
redBtn.addActionListener(this);
greenBtn = new JToggleButton("green");
greenBtn.addActionListener(this);
blueBtn = new JToggleButton("blue");
blueBtn.addActionListener(this);
display = new JPanel();
display.setPreferredSize(new Dimension(120, 120));
display.setBorder(LineBorder.createGrayLineBorder());
display.setBackground(Color.black);
createLayout(redBtn, greenBtn, blueBtn, display);
setTitle("JToggleButton");
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup()
.addGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addComponent(arg[1])
.addComponent(arg[2]))
.addPreferredGap(UNRELATED)
.addComponent(arg[3])
);
gl.setVerticalGroup(gl.createParallelGroup(CENTER)
.addGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addComponent(arg[1])
.addComponent(arg[2]))
.addComponent(arg[3])
);
gl.linkSize(redBtn, greenBtn, blueBtn);
pack();
}
@Override
public void actionPerformed(ActionEvent e) {
var color = display.getBackground();
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
if (e.getActionCommand().equals("red")) {
if (red == 0) {
red = 255;
} else {
red = 0;
}
}
if (e.getActionCommand().equals("green")) {
if (green == 0) {
green = 255;
} else {
green = 0;
}
}
if (e.getActionCommand().equals("blue")) {
if (blue == 0) {
blue = 255;
} else {
blue = 0;
}
}
var setCol = new Color(red, green, blue);
display.setBackground(setCol);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new ToggleButtonEx();
ex.setVisible(true);
});
}
}
该示例有三个切换按钮和一个面板。 我们将显示面板的背景颜色设置为黑色。 切换按钮将切换颜色值的红色、绿色和蓝色部分。 背景颜色将取决于我们按下了哪些切换按钮。
redBtn = new JToggleButton("red");
redBtn.addActionListener(this);
在这里,我们创建一个切换按钮并为其设置一个动作侦听器。
display = new JPanel(); display.setPreferredSize(new Dimension(120, 120)); display.setBorder(LineBorder.createGrayLineBorder()); display.setBackground(Color.black);
这是显示由切换按钮混合的颜色值的面板。 我们设置其首选大小(默认为非常小),将边框线更改为灰色,并设置初始背景颜色。
var color = display.getBackground(); int red = color.getRed(); int green = color.getGreen(); int blue = color.getBlue();
在 actionPerformed() 方法中,我们确定显示背景颜色的红色、绿色和蓝色部分的当前值。
if (e.getActionCommand().equals("red")) {
if (red == 0) {
red = 255;
} else {
red = 0;
}
}
我们确定按下了哪个按钮,并相应地更新 RGB 值的颜色部分。
var setCol = new Color(red, green, blue); display.setBackground(setCol);
创建新颜色,并将显示面板更新为新颜色。
JList 组件
JList 是一个显示对象列表的组件。 它允许用户选择一个或多个项目。
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
public class ListEx extends JFrame {
private JLabel label;
private JScrollPane spane;
public ListEx() {
initUI();
}
private void initUI() {
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
var fonts = ge.getAvailableFontFamilyNames();
var list = new JList(fonts);
list.addListSelectionListener(e -> {
if (!e.getValueIsAdjusting()) {
var name = (String) list.getSelectedValue();
var font = new Font(name, Font.PLAIN, 12);
label.setFont(font);
}
});
spane = new JScrollPane();
spane.getViewport().add(list);
label = new JLabel("Aguirre, der Zorn Gottes");
label.setFont(new Font("Serif", Font.PLAIN, 12));
createLayout(spane, label);
setTitle("JList");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addComponent(arg[1])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addComponent(arg[1])
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new ListEx();
ex.setVisible(true);
});
}
}
在我们的示例中,我们将显示 JList 和 JLabel 组件。 列表组件包含系统上所有可用字体系列名称的列表。 如果我们从列表中选择一个项目,则标签将以所选字体显示。
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); var fonts = ge.getAvailableFontFamilyNames();
在这里,我们获取系统上所有可能的字体系列名称。
var list = new JList(fonts);
我们创建一个 JList 组件。
list.addListSelectionListener(e -> {
if (!e.getValueIsAdjusting()) {
...
}
});
列表选择中的事件被分组。 我们接收选择和取消选择项目的事件。 为了仅过滤选择事件,我们使用 getValueIsAdjusting() 方法。
var name = (String) list.getSelectedValue(); var font = new Font(name, Font.PLAIN, 12); label.setFont(font);
我们获取选定的项目并为标签设置新字体。
spane = new JScrollPane(); spane.getViewport().add(list);
JList 可以包含比在窗口上实际可以显示的更多项目。 默认情况下,它不可滚动。 我们将列表放入 JScrollPane 中以使其可滚动。
JTabbedPane 组件
JTabbedPane 是一个组件,允许用户通过单击选项卡在组件组之间切换。
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import java.awt.EventQueue;
public class TabbedPaneEx extends JFrame {
public TabbedPaneEx() {
initUI();
}
private void initUI() {
var tabbedPane = new JTabbedPane();
tabbedPane.addTab("First", createPanel("First panel"));
tabbedPane.addTab("Second", createPanel("Second panel"));
tabbedPane.addTab("Third", createPanel("Third panel"));
createLayout(tabbedPane);
setTitle("JTabbedPane");
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private JPanel createPanel(String text) {
var panel = new JPanel();
var lbl = new JLabel(text);
panel.add(lbl);
return panel;
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
);
gl.setVerticalGroup(gl.createParallelGroup()
.addComponent(arg[0])
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new TabbedPaneEx();
ex.setVisible(true);
});
}
}
在该示例中,我们有一个带三个选项卡的选项卡窗格。 每个选项卡显示一个带有标签的面板。
var tabbedPane = new JTabbedPane();
创建一个新的 JTabbedPane。
tabbedPane.addTab("First", createPanel("First panel"));
使用 addTab() 方法,我们创建一个新选项卡。 第一个参数是选项卡显示的标题。 第二个参数是要在单击选项卡时显示的组件。
JTextArea 组件
JTextArea 是一个显示纯文本的多行文本区域。 它是用于处理文本的轻量级组件。 该组件不处理滚动。 对于此任务,我们使用 JScrollPane 组件。
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import java.awt.Dimension;
import java.awt.EventQueue;
public class TextAreaEx extends JFrame {
public TextAreaEx() {
initUI();
}
private void initUI() {
var area = new JTextArea();
var spane = new JScrollPane(area);
area.setLineWrap(true);
area.setWrapStyleWord(true);
createLayout(spane);
setTitle("JTextArea");
setSize(new Dimension(350, 300));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createParallelGroup()
.addComponent(arg[0])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new TextAreaEx();
ex.setVisible(true);
});
}
}
该示例显示一个简单的 JTextArea 组件。
var area = new JTextArea();
这是 JTextArea 组件的构造函数。
var spane = new JScrollPane(area);
为了使文本可滚动,我们将 JTextArea 组件放入 JScrollPane 组件中。
area.setLineWrap(true);
setLineWrap() 使得如果行太长而无法适应文本区域的宽度,则换行。
area.setWrapStyleWord(true);
在这里,我们指定如何包装行。 在我们的例子中,行将在单词边界(空格)处换行。
JTextPane 组件
JTextPane 组件是一个更高级的组件,用于处理文本。 该组件可以对文本执行一些复杂的格式化操作。 它可以显示 HTML 文档。
<!DOCTYPE html>
<html>
<head>
<title>Simple HTML document</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<h2>A simple HTML document</h2>
<p>
<em>JTextPane</em> can display HTML documents.
</p>
<br>
<pre>
JScrollPane pane = new JScrollPane();
JTextPane textpane = new JTextPane();
textpane.setContentType("text/html");
textpane.setEditable(false);
</pre>
<br>
<p>The Java Swing tutorial, 2018</p>
</body>
</html>
这是我们要加载到 JTextPane 组件中的 HTML 代码。 该组件不处理滚动。
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import java.awt.EventQueue;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class TextPaneEx extends JFrame {
private JTextPane textPane;
public TextPaneEx() {
initUI();
}
private void initUI() {
textPane = new JTextPane();
var spane = new JScrollPane(textPane);
textPane.setContentType("text/html");
textPane.setEditable(false);
loadFile();
createLayout(spane);
setTitle("JTextPane");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
);
gl.setVerticalGroup(gl.createParallelGroup()
.addComponent(arg[0])
);
pack();
}
private void loadFile() {
try {
var curDir = System.getProperty("user.dir") + "/";
textPane.setPage("File:///" + curDir + "test.html");
} catch (IOException ex) {
Logger.getLogger(this.getName()).log(Level.SEVERE,
"Failed to load file", ex);
}
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new TextPaneEx();
ex.setVisible(true);
});
}
}
在我们的示例中,我们显示一个 JTextPane 组件并加载 HTML 文档。 HTML 文档是从当前工作目录加载的。 当我们使用 IDE 时,它是一个项目目录。 该示例显示了该组件的格式化功能。
var textpane = new JTextPane();
textpane.setContentType("text/html");
textpane.setEditable(false);
我们创建一个 JTextPane 组件,将该组件的内容设置为 HTML 文档,并禁用编辑。
private void loadFile() {
try {
var curDir = System.getProperty("user.dir") + "/";
textPane.setPage("File:///" + curDir + "test.html");
} catch (IOException ex) {
Logger.getLogger(this.getName()).log(Level.SEVERE,
"Failed to load file", ex);
}
}
在这里,我们确定用户的当前工作目录。 我们将一个 HTML 文档加载到窗格中。
在本章中,我们继续介绍基本的 Swing 组件,包括 JCheckBox、JRadioButton、JSlider、JComboBox、JProgressBar、JToggleButton、JList、JTabbedPane、JTextArea 和 JTextPane。