Java Swing 首个程序
原文: http://zetcode.com/tutorials/javaswingtutorial/firstprograms/
在本章中,我们将对第一个 Swing 程序进行编程。 我们创建了第一个简单的应用,展示了如何使用“退出”按钮终止应用,显示框架图标,显示工具提示,使用助记符以及显示标准颜色。
Java Swing 组件是 Java Swing 应用的基本构建块。 在本章中,我们将使用JFrame
,JButton
和JLabel
组件。 JFrame
是带有标题和边框的顶层窗口。 它用于组织其他组件,通常称为子组件。
JButton
是用于执行动作的按钮。 JLabel
是用于支付短文本字符串或图像或两者的组件。
第一个 Swing 示例
第一个示例在屏幕上显示一个基本窗口。
com/zetcode/SimpleEx.java
package com.zetcode;
import java.awt.EventQueue;
import javax.swing.JFrame;
public class SimpleEx extends JFrame {
public SimpleEx() {
initUI();
}
private void initUI() {
setTitle("Simple example");
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new SimpleEx();
ex.setVisible(true);
});
}
}
尽管这段代码很短,但是应用窗口可以做很多事情。 可以调整大小,最大化或最小化。 随之而来的所有复杂性对应用员都是隐藏的。
import java.awt.EventQueue;
import javax.swing.JFrame;
在这里,我们导入将在代码示例中使用的 Swing 类。
public class SimpleEx extends JFrame {
SimpleEx
继承自JFrame
组件。 JFrame
是顶级容器。 容器的基本目的是容纳应用的组件。
public SimpleEx() {
initUI();
}
好的编程习惯是不要将应用代码放入构造器中,而是将任务委托给特定的方法。
setTitle("Simple example");
在这里,我们使用setTitle()
方法设置窗口的标题。
setSize(300, 200);
setSize()
将窗口的大小调整为 300 像素宽和 200 像素高。
setLocationRelativeTo(null);
这条线使窗口在屏幕上居中。
setDefaultCloseOperation(EXIT_ON_CLOSE);
如果单击标题栏的“关闭”按钮,则此setDefaultCloseOperation()
将关闭窗口。 默认情况下,如果我们单击按钮,则不会发生任何事情。
EventQueue.invokeLater(() -> {
var ex = new SimpleEx();
ex.setVisible(true);
});
我们创建代码示例的实例,并使它在屏幕上可见。 invokeLater()
方法将应用放置在 Swing 事件队列中。 它用于确保所有 UI 更新都是并发安全的。 换句话说,这是为了防止 GUI 在某些情况下挂起。
图:简单 example
JButton
示例
在下一个示例中,我们将有一个按钮。 当我们单击按钮时,应用终止。
com/zetcode/QuitButtonEx.java
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.awt.EventQueue;
public class QuitButtonEx extends JFrame {
public QuitButtonEx() {
initUI();
}
private void initUI() {
var quitButton = new JButton("Quit");
quitButton.addActionListener((event) -> System.exit(0));
createLayout(quitButton);
setTitle("Quit button");
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new QuitButtonEx();
ex.setVisible(true);
});
}
}
我们将JButton
放置在窗口上,然后向该按钮添加一个动作监听器。
var quitButton = new JButton("Quit");
在这里,我们创建一个按钮组件。 此构造器将字符串标签作为参数。
quitButton.addActionListener((event) -> System.exit(0));
我们将一个动作监听器插入按钮。 该操作通过调用System.exit()
方法来终止应用。
createLayout(quitButton);
子组件需要放入容器中。 我们将任务委托给createLayout()
方法。
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
JFrame
的内容窗格是放置子组件的区域。 子级由专门的不可见组件(称为布局管理器)组织。 内容窗格的默认布局管理器是BorderLayout
管理器。 这个管理器很简单。 在本教程中,我们使用GroupLayout
管理器,它功能更强大,更灵活。
gl.setAutoCreateContainerGaps(true);
setAutoCreateContainerGaps()
方法会在组件和容器边缘之间产生间隙。 空间或间隙是每个应用设计的重要组成部分。
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
);
GroupLayout
管理器独立定义每个大小的布局。 第一步,我们沿着水平轴布置组件; 在另一步骤中,我们沿垂直轴布置组件。 在两种布局中,我们都可以顺序或并行排列组件。 在水平布局中,一行组件称为顺序组,而一列组件称为并行组。 在垂直布局中,一列组件称为顺序组,一排组件称为并行组。
在我们的示例中,我们只有一个按钮,因此布局非常简单。 对于每个大小,我们将按钮组件作为参数调用addComponent()
方法。 (必须为两个维度都添加每个子组件。)
图:退出按钮
JFrame
图标
在下面的示例中,我们将在框架上显示一个图标。 它显示在标题栏的左侧。
com/zetcode/FrameIconEx.java
package com.zetcode;
import java.awt.EventQueue;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
public class FrameIconEx extends JFrame {
public FrameIconEx() {
initUI();
}
private void initUI() {
var webIcon = new ImageIcon("src/resources/web.png");
setIconImage(webIcon.getImage());
setTitle("Icon");
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new FrameIconEx();
ex.setVisible(true);
});
}
}
ImageIcon
用于创建图标。 web.png
是一个22x22px
的小图像文件。
var webIcon = new ImageIcon("src/resources/web.png");
我们从位于项目根目录中的 PNG 文件创建一个ImageIcon
。
setIconImage(webIcon.getImage());
setIconImage()
设置要显示为该窗口图标的图像。 getImage()
返回图标的Image
。
图:图标
Swing 工具提示
工具提示是内部应用帮助系统的一部分。 如果将鼠标指针悬停在设置了工具提示的对象上,则 Swing 将显示一个小窗口。
com/zetcode/TooltipEx.java
package com.zetcode;
import java.awt.EventQueue;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TooltipEx extends JFrame {
public TooltipEx() {
initUI();
}
private void initUI() {
var btn = new JButton("Button");
btn.setToolTipText("A button component");
createLayout(btn);
setTitle("Tooltip");
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void createLayout(JComponent... arg) {
var pane = (JPanel) getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
pane.setToolTipText("Content pane");
gl.setAutoCreateContainerGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addGap(200)
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addGap(120)
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new TooltipEx();
ex.setVisible(true);
});
}
}
在示例中,我们为框架和按钮设置了一个工具提示。
btn.setToolTipText("A button component");
要启用工具提示,我们调用setTooltipText()
方法。
var pane = (JPanel) getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
内容窗格是JPanel
组件的实例。 getContentPane()
方法返回Container
类型。 由于设置工具提示需要JComponent
实例,因此我们将对象投射到JPanel
。
pane.setToolTipText("Content pane");
为内容窗格设置了一个工具提示。
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addGap(200)
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addGap(120)
);
我们将addGap()
方法用于水平和垂直大小。 它在按钮的右侧和底部创建了一些空间。 (目的是增加窗口的初始大小。)
pack();
pack()
方法根据其组件的大小自动调整JFrame
的大小。 它也考虑了定义的空间。 我们的窗口将显示按钮和我们通过addGap()
方法设置的空间。
图:工具提示
Swing 助记符
助记符是用于激活支持助记符的组件的快捷键。 例如,它们可以与标签,按钮或菜单项一起使用。
com/zetcode/MnemonicEx.java
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import java.awt.EventQueue;
import java.awt.event.KeyEvent;
public class MnemonicEx extends JFrame {
public MnemonicEx() {
initUI();
}
private void initUI() {
var btn = new JButton("Button");
btn.addActionListener((event) -> System.out.println("Button pressed"));
btn.setMnemonic(KeyEvent.VK_B);
createLayout(btn);
setTitle("Mnemonics");
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void createLayout(JComponent... arg) {
var pane = getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
gl.setAutoCreateContainerGaps(true);
gl.setHorizontalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addGap(200)
);
gl.setVerticalGroup(gl.createParallelGroup()
.addComponent(arg[0])
.addGap(200)
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new MnemonicEx();
ex.setVisible(true);
});
}
}
我们有一个带有动作监听器的按钮。 我们为此按钮设置了一个助记符。 可以使用 Alt + B
键盘快捷键激活。
btn.setMnemonic(KeyEvent.VK_B);
setMnemonic()
方法为按钮设置键盘助记符。 助记键由KeyEvent
类中的虚拟键代码指定。 助记符与外观的无鼠标修饰符(通常 Alt
)结合在一起。
目前,有三种激活按钮的方法:单击鼠标左键, Alt + B
快捷键以及空格键(按钮具有焦点)。 空格键绑定是由 Swing 自动创建的。 (在“金属”外观下,焦点由按钮标签周围的小矩形直观地表示。)
Swing 标准色
Color
类定义 13 种颜色值,包括红色,绿色,蓝色和黄色。
com/zetcode/StandardColoursEx.java
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.util.ArrayList;
class MyLabel extends JLabel {
public MyLabel() {
super("", null, LEADING);
}
@Override
public boolean isOpaque() {
return true;
}
}
public class StandardColoursEx extends JFrame {
public StandardColoursEx() {
initUI();
}
private void initUI() {
Color[] stdCols = { Color.black, Color.blue, Color.cyan,
Color.darkGray, Color.gray, Color.green, Color.lightGray,
Color.magenta, Color.orange, Color.pink, Color.red,
Color.white, Color.yellow };
var labels = new ArrayList<JLabel>();
for (var col : stdCols) {
var lbl = createColouredLabel(col);
labels.add(lbl);
}
createLayout(labels.toArray(new JLabel[0]));
setTitle("Standard colours");
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private JLabel createColouredLabel(Color col) {
var lbl = new MyLabel();
lbl.setMinimumSize(new Dimension(90, 40));
lbl.setBackground(col);
return lbl;
}
private void createLayout(JLabel[] labels) {
var pane = (JPanel) getContentPane();
var gl = new GroupLayout(pane);
pane.setLayout(gl);
pane.setToolTipText("Content pane");
gl.setAutoCreateContainerGaps(true);
gl.setAutoCreateGaps(true);
gl.setHorizontalGroup(gl.createParallelGroup()
.addGroup(gl.createSequentialGroup()
.addComponent(labels[0])
.addComponent(labels[1])
.addComponent(labels[2])
.addComponent(labels[3]))
.addGroup(gl.createSequentialGroup()
.addComponent(labels[4])
.addComponent(labels[5])
.addComponent(labels[6])
.addComponent(labels[7]))
.addGroup(gl.createSequentialGroup()
.addComponent(labels[8])
.addComponent(labels[9])
.addComponent(labels[10])
.addComponent(labels[11]))
.addComponent(labels[12])
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addGroup(gl.createParallelGroup()
.addComponent(labels[0])
.addComponent(labels[1])
.addComponent(labels[2])
.addComponent(labels[3]))
.addGroup(gl.createParallelGroup()
.addComponent(labels[4])
.addComponent(labels[5])
.addComponent(labels[6])
.addComponent(labels[7]))
.addGroup(gl.createParallelGroup()
.addComponent(labels[8])
.addComponent(labels[9])
.addComponent(labels[10])
.addComponent(labels[11]))
.addComponent(labels[12])
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new StandardColoursEx();
ex.setVisible(true);
});
}
}
该示例显示了 13 个JLabel
组件; 每个标签具有不同的背景色。 JLabel
通常用于显示文本; 但它也可以显示颜色。
class MyLabel extends JLabel {
public MyLabel() {
super("", null, LEADING);
}
@Override
public boolean isOpaque() {
return true;
}
}
JLabel
组件是具有默认透明背景的特定组件。 为了在标签上绘图,我们重写了isOpaque()
方法,该方法返回true
。
Color[] stdCols = { Color.black, Color.blue, Color.cyan,
Color.darkGray, Color.gray, Color.green, Color.lightGray,
Color.magenta, Color.orange, Color.pink, Color.red,
Color.white, Color.yellow };
这里我们有一个内置的静态颜色值数组。
var labels = new ArrayList<JLabel>();
for (var col : stdCols) {
var lbl = createColouredLabel(col);
labels.add(lbl);
}
将创建JLabel
组件的列表。 使用createColouredLabel()
方法创建一个新标签。
public JLabel createColouredLabel(Color col) {
var lbl = new MyLabel();
lbl.setMinimumSize(new Dimension(90, 40));
lbl.setBackground(col);
return lbl;
}
createColouredLabel()
方法创建一个新标签。 我们为标签设置了最小大小。 setBackground()
设置组件的背景色。
图:标准颜色
Swing 鼠标移动事件
MouseMotionAdapter
用于接收鼠标运动事件。
com/zetcode/MouseMoveEventEx.java
package com.zetcode;
import javax.swing.GroupLayout;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
public class MouseMoveEventEx extends JFrame {
private JLabel coords;
public MouseMoveEventEx() {
initUI();
}
private void initUI() {
coords = new JLabel("");
createLayout(coords);
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
int x = e.getX();
int y = e.getY();
var text = String.format("x: %d, y: %d", x, y);
coords.setText(text);
}
});
setTitle("Mouse move events");
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
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])
.addGap(250)
);
gl.setVerticalGroup(gl.createSequentialGroup()
.addComponent(arg[0])
.addGap(130)
);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
var ex = new MouseMoveEventEx();
ex.setVisible(true);
});
}
}
在示例中,我们在标签组件中显示鼠标指针的坐标。
addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
int x = e.getX();
int y = e.getY();
var text = String.format("x: %d, y: %d", x, y);
coords.setText(text);
}
});
我们重写了适配器的moseMoved()
方法。 从MouseEvent
对象中,我们获得鼠标指针的 x 和 y 坐标,构建一个字符串并将其设置为标签。
图:鼠标移动事件
在本章中,我们创建了一些简单的 Java Swing 程序。