原文: http://zetcode.com/tutorials/javaswingtutorial/firstprograms/

在本章中,我们将对第一个 Swing 程序进行编程。 我们创建了第一个简单的应用,展示了如何使用“退出”按钮终止应用,显示框架图标,显示工具提示,使用助记符以及显示标准颜色。

Tweet

Java Swing 组件是 Java Swing 应用的基本构建块。 在本章中,我们将使用JFrameJButtonJLabel组件。 JFrame是带有标题和边框的顶层窗口。 它用于组织其他组件,通常称为子组件。

JButton是用于执行动作的按钮。 JLabel是用于支付短文本字符串或图像或两者的组件。

第一个 Swing 示例

第一个示例在屏幕上显示一个基本窗口。

com/zetcode/SimpleEx.java

  1. package com.zetcode;
  2. import java.awt.EventQueue;
  3. import javax.swing.JFrame;
  4. public class SimpleEx extends JFrame {
  5. public SimpleEx() {
  6. initUI();
  7. }
  8. private void initUI() {
  9. setTitle("Simple example");
  10. setSize(300, 200);
  11. setLocationRelativeTo(null);
  12. setDefaultCloseOperation(EXIT_ON_CLOSE);
  13. }
  14. public static void main(String[] args) {
  15. EventQueue.invokeLater(() -> {
  16. var ex = new SimpleEx();
  17. ex.setVisible(true);
  18. });
  19. }
  20. }

尽管这段代码很短,但是应用窗口可以做很多事情。 可以调整大小,最大化或最小化。 随之而来的所有复杂性对应用员都是隐藏的。

  1. import java.awt.EventQueue;
  2. import javax.swing.JFrame;

在这里,我们导入将在代码示例中使用的 Swing 类。

  1. public class SimpleEx extends JFrame {

SimpleEx继承自JFrame组件。 JFrame是顶级容器。 容器的基本目的是容纳应用的组件。

  1. public SimpleEx() {
  2. initUI();
  3. }

好的编程习惯是不要将应用代码放入构造器中,而是将任务委托给特定的方法。

  1. setTitle("Simple example");

在这里,我们使用setTitle()方法设置窗口的标题。

  1. setSize(300, 200);

setSize()将窗口的大小调整为 300 像素宽和 200 像素高。

  1. setLocationRelativeTo(null);

这条线使窗口在屏幕上居中。

  1. setDefaultCloseOperation(EXIT_ON_CLOSE);

如果单击标题栏的“关闭”按钮,则此setDefaultCloseOperation()将关闭窗口。 默认情况下,如果我们单击按钮,则不会发生任何事情。

  1. EventQueue.invokeLater(() -> {
  2. var ex = new SimpleEx();
  3. ex.setVisible(true);
  4. });

我们创建代码示例的实例,并使它在屏幕上可见。 invokeLater()方法将应用放置在 Swing 事件队列中。 它用于确保所有 UI 更新都是并发安全的。 换句话说,这是为了防止 GUI 在某些情况下挂起。

Java Swing 首个程序 - 图1

图:简单 example

JButton示例

在下一个示例中,我们将有一个按钮。 当我们单击按钮时,应用终止。

com/zetcode/QuitButtonEx.java

  1. package com.zetcode;
  2. import javax.swing.GroupLayout;
  3. import javax.swing.JButton;
  4. import javax.swing.JComponent;
  5. import javax.swing.JFrame;
  6. import java.awt.EventQueue;
  7. public class QuitButtonEx extends JFrame {
  8. public QuitButtonEx() {
  9. initUI();
  10. }
  11. private void initUI() {
  12. var quitButton = new JButton("Quit");
  13. quitButton.addActionListener((event) -> System.exit(0));
  14. createLayout(quitButton);
  15. setTitle("Quit button");
  16. setSize(300, 200);
  17. setLocationRelativeTo(null);
  18. setDefaultCloseOperation(EXIT_ON_CLOSE);
  19. }
  20. private void createLayout(JComponent... arg) {
  21. var pane = getContentPane();
  22. var gl = new GroupLayout(pane);
  23. pane.setLayout(gl);
  24. gl.setAutoCreateContainerGaps(true);
  25. gl.setHorizontalGroup(gl.createSequentialGroup()
  26. .addComponent(arg[0])
  27. );
  28. gl.setVerticalGroup(gl.createSequentialGroup()
  29. .addComponent(arg[0])
  30. );
  31. }
  32. public static void main(String[] args) {
  33. EventQueue.invokeLater(() -> {
  34. var ex = new QuitButtonEx();
  35. ex.setVisible(true);
  36. });
  37. }
  38. }

我们将JButton放置在窗口上,然后向该按钮添加一个动作监听器。

  1. var quitButton = new JButton("Quit");

在这里,我们创建一个按钮组件。 此构造器将字符串标签作为参数。

  1. quitButton.addActionListener((event) -> System.exit(0));

我们将一个动作监听器插入按钮。 该操作通过调用System.exit()方法来终止应用。

  1. createLayout(quitButton);

子组件需要放入容器中。 我们将任务委托给createLayout()方法。

  1. var pane = getContentPane();
  2. var gl = new GroupLayout(pane);
  3. pane.setLayout(gl);

JFrame的内容窗格是放置子组件的区域。 子级由专门的不可见组件(称为布局管理器)组织。 内容窗格的默认布局管理器是BorderLayout管理器。 这个管理器很简单。 在本教程中,我们使用GroupLayout管理器,它功能更强大,更灵活。

  1. gl.setAutoCreateContainerGaps(true);

setAutoCreateContainerGaps()方法会在组件和容器边缘之间产生间隙。 空间或间隙是每个应用设计的重要组成部分。

  1. gl.setHorizontalGroup(gl.createSequentialGroup()
  2. .addComponent(arg[0])
  3. );
  4. gl.setVerticalGroup(gl.createSequentialGroup()
  5. .addComponent(arg[0])
  6. );

GroupLayout管理器独立定义每个大小的布局。 第一步,我们沿着水平轴布置组件; 在另一步骤中,我们沿垂直轴布置组件。 在两种布局中,我们都可以顺序或并行排列组件。 在水平布局中,一行组件称为顺序组,而一列组件称为并行组。 在垂直布局中,一列组件称为顺序组,一排组件称为并行组。

在我们的示例中,我们只有一个按钮,因此布局非常简单。 对于每个大小,我们将按钮组件作为参数调用addComponent()方法。 (必须为两个维度都添加每个子组件。)

Java Swing 首个程序 - 图2

图:退出按钮

JFrame图标

在下面的示例中,我们将在框架上显示一个图标。 它显示在标题栏的左侧。

com/zetcode/FrameIconEx.java

  1. package com.zetcode;
  2. import java.awt.EventQueue;
  3. import javax.swing.ImageIcon;
  4. import javax.swing.JFrame;
  5. public class FrameIconEx extends JFrame {
  6. public FrameIconEx() {
  7. initUI();
  8. }
  9. private void initUI() {
  10. var webIcon = new ImageIcon("src/resources/web.png");
  11. setIconImage(webIcon.getImage());
  12. setTitle("Icon");
  13. setSize(300, 200);
  14. setLocationRelativeTo(null);
  15. setDefaultCloseOperation(EXIT_ON_CLOSE);
  16. }
  17. public static void main(String[] args) {
  18. EventQueue.invokeLater(() -> {
  19. var ex = new FrameIconEx();
  20. ex.setVisible(true);
  21. });
  22. }
  23. }

ImageIcon用于创建图标。 web.png是一个22x22px的小图像文件。

  1. var webIcon = new ImageIcon("src/resources/web.png");

我们从位于项目根目录中的 PNG 文件创建一个ImageIcon

  1. setIconImage(webIcon.getImage());

setIconImage()设置要显示为该窗口图标的图像。 getImage()返回图标的Image

Java Swing 首个程序 - 图3

图:图标

Swing 工具提示

工具提示是内部应用帮助系统的一部分。 如果将鼠标指针悬停在设置了工具提示的对象上,则 Swing 将显示一个小窗口。

com/zetcode/TooltipEx.java

  1. package com.zetcode;
  2. import java.awt.EventQueue;
  3. import javax.swing.GroupLayout;
  4. import javax.swing.JButton;
  5. import javax.swing.JComponent;
  6. import javax.swing.JFrame;
  7. import javax.swing.JPanel;
  8. public class TooltipEx extends JFrame {
  9. public TooltipEx() {
  10. initUI();
  11. }
  12. private void initUI() {
  13. var btn = new JButton("Button");
  14. btn.setToolTipText("A button component");
  15. createLayout(btn);
  16. setTitle("Tooltip");
  17. setLocationRelativeTo(null);
  18. setDefaultCloseOperation(EXIT_ON_CLOSE);
  19. }
  20. private void createLayout(JComponent... arg) {
  21. var pane = (JPanel) getContentPane();
  22. var gl = new GroupLayout(pane);
  23. pane.setLayout(gl);
  24. pane.setToolTipText("Content pane");
  25. gl.setAutoCreateContainerGaps(true);
  26. gl.setHorizontalGroup(gl.createSequentialGroup()
  27. .addComponent(arg[0])
  28. .addGap(200)
  29. );
  30. gl.setVerticalGroup(gl.createSequentialGroup()
  31. .addComponent(arg[0])
  32. .addGap(120)
  33. );
  34. pack();
  35. }
  36. public static void main(String[] args) {
  37. EventQueue.invokeLater(() -> {
  38. var ex = new TooltipEx();
  39. ex.setVisible(true);
  40. });
  41. }
  42. }

在示例中,我们为框架和按钮设置了一个工具提示。

  1. btn.setToolTipText("A button component");

要启用工具提示,我们调用setTooltipText()方法。

  1. var pane = (JPanel) getContentPane();
  2. var gl = new GroupLayout(pane);
  3. pane.setLayout(gl);

内容窗格是JPanel组件的实例。 getContentPane()方法返回Container类型。 由于设置工具提示需要JComponent实例,因此我们将对象投射到JPanel

  1. pane.setToolTipText("Content pane");

为内容窗格设置了一个工具提示。

  1. gl.setHorizontalGroup(gl.createSequentialGroup()
  2. .addComponent(arg[0])
  3. .addGap(200)
  4. );
  5. gl.setVerticalGroup(gl.createSequentialGroup()
  6. .addComponent(arg[0])
  7. .addGap(120)
  8. );

我们将addGap()方法用于水平和垂直大小。 它在按钮的右侧和底部创建了一些空间。 (目的是增加窗口的初始大小。)

  1. pack();

pack()方法根据其组件的大小自动调整JFrame的大小。 它也考虑了定义的空间。 我们的窗口将显示按钮和我们通过addGap()方法设置的空间。

Java Swing 首个程序 - 图4

图:工具提示

Swing 助记符

助记符是用于激活支持助记符的组件的快捷键。 例如,它们可以与标签,按钮或菜单项一起使用。

com/zetcode/MnemonicEx.java

  1. package com.zetcode;
  2. import javax.swing.GroupLayout;
  3. import javax.swing.JButton;
  4. import javax.swing.JComponent;
  5. import javax.swing.JFrame;
  6. import java.awt.EventQueue;
  7. import java.awt.event.KeyEvent;
  8. public class MnemonicEx extends JFrame {
  9. public MnemonicEx() {
  10. initUI();
  11. }
  12. private void initUI() {
  13. var btn = new JButton("Button");
  14. btn.addActionListener((event) -> System.out.println("Button pressed"));
  15. btn.setMnemonic(KeyEvent.VK_B);
  16. createLayout(btn);
  17. setTitle("Mnemonics");
  18. setLocationRelativeTo(null);
  19. setDefaultCloseOperation(EXIT_ON_CLOSE);
  20. }
  21. private void createLayout(JComponent... arg) {
  22. var pane = getContentPane();
  23. var gl = new GroupLayout(pane);
  24. pane.setLayout(gl);
  25. gl.setAutoCreateContainerGaps(true);
  26. gl.setHorizontalGroup(gl.createSequentialGroup()
  27. .addComponent(arg[0])
  28. .addGap(200)
  29. );
  30. gl.setVerticalGroup(gl.createParallelGroup()
  31. .addComponent(arg[0])
  32. .addGap(200)
  33. );
  34. pack();
  35. }
  36. public static void main(String[] args) {
  37. EventQueue.invokeLater(() -> {
  38. var ex = new MnemonicEx();
  39. ex.setVisible(true);
  40. });
  41. }
  42. }

我们有一个带有动作监听器的按钮。 我们为此按钮设置了一个助记符。 可以使用 Alt + B 键盘快捷键激活。

  1. btn.setMnemonic(KeyEvent.VK_B);

setMnemonic()方法为按钮设置键盘助记符。 助记键由KeyEvent类中的虚拟键代码指定。 助记符与外观的无鼠标修饰符(通常 Alt )结合在一起。

目前,有三种激活按钮的方法:单击鼠标左键, Alt + B快捷键以及空格键(按钮具有焦点)。 空格键绑定是由 Swing 自动创建的。 (在“金属”外观下,焦点由按钮标签周围的小矩形直观地表示。)

Swing 标准色

Color类定义 13 种颜色值,包括红色,绿色,蓝色和黄色。

com/zetcode/StandardColoursEx.java

  1. package com.zetcode;
  2. import javax.swing.GroupLayout;
  3. import javax.swing.JFrame;
  4. import javax.swing.JLabel;
  5. import javax.swing.JPanel;
  6. import java.awt.Color;
  7. import java.awt.Dimension;
  8. import java.awt.EventQueue;
  9. import java.util.ArrayList;
  10. class MyLabel extends JLabel {
  11. public MyLabel() {
  12. super("", null, LEADING);
  13. }
  14. @Override
  15. public boolean isOpaque() {
  16. return true;
  17. }
  18. }
  19. public class StandardColoursEx extends JFrame {
  20. public StandardColoursEx() {
  21. initUI();
  22. }
  23. private void initUI() {
  24. Color[] stdCols = { Color.black, Color.blue, Color.cyan,
  25. Color.darkGray, Color.gray, Color.green, Color.lightGray,
  26. Color.magenta, Color.orange, Color.pink, Color.red,
  27. Color.white, Color.yellow };
  28. var labels = new ArrayList<JLabel>();
  29. for (var col : stdCols) {
  30. var lbl = createColouredLabel(col);
  31. labels.add(lbl);
  32. }
  33. createLayout(labels.toArray(new JLabel[0]));
  34. setTitle("Standard colours");
  35. setLocationRelativeTo(null);
  36. setDefaultCloseOperation(EXIT_ON_CLOSE);
  37. }
  38. private JLabel createColouredLabel(Color col) {
  39. var lbl = new MyLabel();
  40. lbl.setMinimumSize(new Dimension(90, 40));
  41. lbl.setBackground(col);
  42. return lbl;
  43. }
  44. private void createLayout(JLabel[] labels) {
  45. var pane = (JPanel) getContentPane();
  46. var gl = new GroupLayout(pane);
  47. pane.setLayout(gl);
  48. pane.setToolTipText("Content pane");
  49. gl.setAutoCreateContainerGaps(true);
  50. gl.setAutoCreateGaps(true);
  51. gl.setHorizontalGroup(gl.createParallelGroup()
  52. .addGroup(gl.createSequentialGroup()
  53. .addComponent(labels[0])
  54. .addComponent(labels[1])
  55. .addComponent(labels[2])
  56. .addComponent(labels[3]))
  57. .addGroup(gl.createSequentialGroup()
  58. .addComponent(labels[4])
  59. .addComponent(labels[5])
  60. .addComponent(labels[6])
  61. .addComponent(labels[7]))
  62. .addGroup(gl.createSequentialGroup()
  63. .addComponent(labels[8])
  64. .addComponent(labels[9])
  65. .addComponent(labels[10])
  66. .addComponent(labels[11]))
  67. .addComponent(labels[12])
  68. );
  69. gl.setVerticalGroup(gl.createSequentialGroup()
  70. .addGroup(gl.createParallelGroup()
  71. .addComponent(labels[0])
  72. .addComponent(labels[1])
  73. .addComponent(labels[2])
  74. .addComponent(labels[3]))
  75. .addGroup(gl.createParallelGroup()
  76. .addComponent(labels[4])
  77. .addComponent(labels[5])
  78. .addComponent(labels[6])
  79. .addComponent(labels[7]))
  80. .addGroup(gl.createParallelGroup()
  81. .addComponent(labels[8])
  82. .addComponent(labels[9])
  83. .addComponent(labels[10])
  84. .addComponent(labels[11]))
  85. .addComponent(labels[12])
  86. );
  87. pack();
  88. }
  89. public static void main(String[] args) {
  90. EventQueue.invokeLater(() -> {
  91. var ex = new StandardColoursEx();
  92. ex.setVisible(true);
  93. });
  94. }
  95. }

该示例显示了 13 个JLabel组件; 每个标签具有不同的背景色。 JLabel通常用于显示文本; 但它也可以显示颜色。

  1. class MyLabel extends JLabel {
  2. public MyLabel() {
  3. super("", null, LEADING);
  4. }
  5. @Override
  6. public boolean isOpaque() {
  7. return true;
  8. }
  9. }

JLabel组件是具有默认透明背景的特定组件。 为了在标签上绘图,我们重写了isOpaque()方法,该方法返回true

  1. Color[] stdCols = { Color.black, Color.blue, Color.cyan,
  2. Color.darkGray, Color.gray, Color.green, Color.lightGray,
  3. Color.magenta, Color.orange, Color.pink, Color.red,
  4. Color.white, Color.yellow };

这里我们有一个内置的静态颜色值数组。

  1. var labels = new ArrayList<JLabel>();
  2. for (var col : stdCols) {
  3. var lbl = createColouredLabel(col);
  4. labels.add(lbl);
  5. }

将创建JLabel组件的列表。 使用createColouredLabel()方法创建一个新标签。

  1. public JLabel createColouredLabel(Color col) {
  2. var lbl = new MyLabel();
  3. lbl.setMinimumSize(new Dimension(90, 40));
  4. lbl.setBackground(col);
  5. return lbl;
  6. }

createColouredLabel()方法创建一个新标签。 我们为标签设置了最小大小。 setBackground()设置组件的背景色。

Java Swing 首个程序 - 图5

图:标准颜色

Swing 鼠标移动事件

MouseMotionAdapter用于接收鼠标运动事件。

com/zetcode/MouseMoveEventEx.java

  1. package com.zetcode;
  2. import javax.swing.GroupLayout;
  3. import javax.swing.JComponent;
  4. import javax.swing.JFrame;
  5. import javax.swing.JLabel;
  6. import java.awt.Container;
  7. import java.awt.EventQueue;
  8. import java.awt.event.MouseEvent;
  9. import java.awt.event.MouseMotionAdapter;
  10. public class MouseMoveEventEx extends JFrame {
  11. private JLabel coords;
  12. public MouseMoveEventEx() {
  13. initUI();
  14. }
  15. private void initUI() {
  16. coords = new JLabel("");
  17. createLayout(coords);
  18. addMouseMotionListener(new MouseMotionAdapter() {
  19. @Override
  20. public void mouseMoved(MouseEvent e) {
  21. super.mouseMoved(e);
  22. int x = e.getX();
  23. int y = e.getY();
  24. var text = String.format("x: %d, y: %d", x, y);
  25. coords.setText(text);
  26. }
  27. });
  28. setTitle("Mouse move events");
  29. setSize(300, 200);
  30. setLocationRelativeTo(null);
  31. setDefaultCloseOperation(EXIT_ON_CLOSE);
  32. }
  33. private void createLayout(JComponent... arg) {
  34. var pane = getContentPane();
  35. var gl = new GroupLayout(pane);
  36. pane.setLayout(gl);
  37. gl.setAutoCreateContainerGaps(true);
  38. gl.setHorizontalGroup(gl.createParallelGroup()
  39. .addComponent(arg[0])
  40. .addGap(250)
  41. );
  42. gl.setVerticalGroup(gl.createSequentialGroup()
  43. .addComponent(arg[0])
  44. .addGap(130)
  45. );
  46. pack();
  47. }
  48. public static void main(String[] args) {
  49. EventQueue.invokeLater(() -> {
  50. var ex = new MouseMoveEventEx();
  51. ex.setVisible(true);
  52. });
  53. }
  54. }

在示例中,我们在标签组件中显示鼠标指针的坐标。

  1. addMouseMotionListener(new MouseMotionAdapter() {
  2. @Override
  3. public void mouseMoved(MouseEvent e) {
  4. super.mouseMoved(e);
  5. int x = e.getX();
  6. int y = e.getY();
  7. var text = String.format("x: %d, y: %d", x, y);
  8. coords.setText(text);
  9. }
  10. });

我们重写了适配器的moseMoved()方法。 从MouseEvent对象中,我们获得鼠标指针的 x 和 y 坐标,构建一个字符串并将其设置为标签。

Java Swing 首个程序 - 图6

图:鼠标移动事件

在本章中,我们创建了一些简单的 Java Swing 程序。