【Java】Swing

历史回顾:曾经的Java桌面应用

0. 前言

Java 桌面应用 一般由 Java Swing 提供。是现在已经淘汰的技术,工作中已经几乎不用了,近几年出的新版的JDK 也已不再支持 Java Swing。那我们为什么还要学习它呢?

其实 Java Swing 也是很帅的,如果您跟我一样没有前端基础,那么单凭Java Swing 就可以用纯 Java 做一些小玩意,这不,最近我的领导就用 GPT + Copilot + Java Swing 半小时就模拟出了一个QQ,帅的咧。

为什么要学习 Java Swing

  • 回顾历史,或许能对现在有新的启发
  • 对于学生考试而言,现在很多大学的Java课程依然涉及Java Swing,帮助考试
  • 学完可以自己做点小型桌面应用
  • 实在想不到写点啥,水一篇文章

参考教程
how2j的Java教程:https://how2j.cn/

如果上述学习的理由与您的情况或您的想法不匹配,那么您可以把这篇文章划走了,有一说一,实际工作真不怎么会用到 Java Swing 了。

1. Java Swing

学习 Swing 这个GUI 技术有个小前提,就是首先要了解:Swing 的窗口是基于 像素和坐标的,下文出现的Location,指的都是像素和坐标。关于GUI 的像素和坐标,读者可事先参考其他资料。

1.1 Hello Swing

使用 Java Swing 其实就是使用 javax.swing 包,直接用包里的类和方法即可,只需要知道什么方法是干什么的就行,具体常见方法我会在下面介绍,学习成本低。

我们首先来个 Hello Swing 吧:

public static void main(String[] args) {
        // 主窗口
        JFrame f = new JFrame("Hello Swing");
        // 设置窗口大小
        f.setSize(400, 300);
        // 主窗口设置位置
        f.setLocation(200, 200);
        // 设置为绝对定位
        f.setLayout(null);
        // 按钮组件
        JButton b = new JButton("Hello");
        // 设置按钮大小和位置
        b.setBounds(50, 50, 280, 30);
        // 添加按钮到主窗口
        f.add(b);
        // 设置主窗口关闭时的操作
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 显示主窗口
        f.setVisible(true);
    }

运行结果:

HelloSwing

1.2 Swing 监听器

Swing 的监听器 可以让我们 对 Swing写出来的GUI界面操作 的 时候, 通过监听器来接收我们的操作信息,并执行相应的操作。

Swing 的监听器分为按钮监听、键盘监听、鼠标监听、适配器等分类。都是为GUI交互而设计的。

1.2.1 按钮监听

通过 button 按钮 绑定 ActionListener 接口的匿名内部类。Swing的代码都很好阅读,我们举个例子:

public static void main(String[] args) {
        // main window
        JFrame f = new JFrame("Hello listener");
        f.setSize(400, 300);
        f.setLocation(200, 200);
        f.setLayout(null);

        // label
        JLabel l = new JLabel();
        // image for test
        ImageIcon icon = new ImageIcon("E:\\Study\\ResourceAndNotes\\Java\\PersonalNotes\\images\\reflect.png");
        // set image
        l.setIcon(icon);
        // set label size and location
        l.setBounds(50, 50, icon.getIconWidth(), icon.getIconHeight());

        // button
        JButton b = new JButton("Click me disappear icon");
        b.setBounds(50, 200, 280, 30);
        // add button listener
        b.addActionListener(e -> l.setVisible(false));

        f.add(l);
        f.add(b);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
        
    }

实现的效果是,点击按钮,图片消失。

1.2.2 键盘监听

使用 KeyListener 实现键盘监听, KeyListener 的方法都是见名知意的,非常好理解:

public static void main(String[] args) {
        // window
        javax.swing.JFrame f = new javax.swing.JFrame("Hello listener");
        f.setSize(400, 300);
        f.setLocation(200, 200);
        f.setLayout(null);

        // label
        javax.swing.JLabel l = new javax.swing.JLabel();
        // image for test
        javax.swing.ImageIcon icon = new javax.swing.ImageIcon("E:\\Study\\ResourceAndNotes\\Java\\PersonalNotes\\images\\reflect.png");
        // set image
        l.setIcon(icon);
        // set label size and location
        l.setBounds(50, 50, icon.getIconWidth(), icon.getIconHeight());
        // add KeyListener
        f.addKeyListener(new java.awt.event.KeyListener() {
            @Override
            public void keyTyped(KeyEvent keyEvent) {
                if (keyEvent.getKeyChar() == 'a') {
                    l.setLocation(l.getX() - 10, l.getY());
                }
                if (keyEvent.getKeyChar() == 'd') {
                    l.setLocation(l.getX() + 10, l.getY());
                }
                if (keyEvent.getKeyChar() == 'w') {
                    l.setLocation(l.getX(), l.getY() - 10);
                }
                if (keyEvent.getKeyChar() == 's') {
                    l.setLocation(l.getX(), l.getY() + 10);
                }
            }
            // key pressed
            @Override
            public void keyPressed(KeyEvent keyEvent) {

            }
            // key released
            @Override
            public void keyReleased(KeyEvent keyEvent) {

            }
        });

        f.add(l);
        f.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
        

}

1.2.3 鼠标监听

MouseListener , 也提供了鼠标按下、释放、退出、进入、点击等事件的监听:

public static void main(String[] args) {
        // window
        javax.swing.JFrame f = new javax.swing.JFrame("Hello listener");
        f.setSize(400, 300);
        f.setLocation(200, 200);
        f.setLayout(null);

        // label
        javax.swing.JLabel l = new javax.swing.JLabel();
        // image for test
        javax.swing.ImageIcon icon = new javax.swing.ImageIcon("E:\\Study\\ResourceAndNotes\\Java\\PersonalNotes\\images\\reflect.png");
        // set image
        l.setIcon(icon);
        // set label size and location
        l.setBounds(50, 50, icon.getIconWidth(), icon.getIconHeight());
        // add MouseListener
        l.addMouseListener(new java.awt.event.MouseListener() {
            @Override
            public void mouseClicked(java.awt.event.MouseEvent mouseEvent) {
                System.out.println("mouse clicked");
            }

            @Override
            public void mousePressed(java.awt.event.MouseEvent mouseEvent) {
                System.out.println("mouse pressed");
            }

            @Override
            public void mouseReleased(java.awt.event.MouseEvent mouseEvent) {
                System.out.println("mouse released");
            }

            @Override
            public void mouseEntered(java.awt.event.MouseEvent mouseEvent) {
                // move image with mouse
                l.setLocation(mouseEvent.getXOnScreen() - icon.getIconWidth() / 2, mouseEvent.getYOnScreen() - icon.getIconHeight() / 2);
            }

            @Override
            public void mouseExited(java.awt.event.MouseEvent mouseEvent) {
                System.out.println("mouse exited");
            }
        });

        f.add(l);
        f.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }

1.3 Swing 容器

我们可以将 一个窗口看作一个容器,组件都放到容器里。

我们上文提到的 Jframe 就是一个容器:

public static void main(String[] args) {
        // 主窗口
        JFrame f = new JFrame("Hello Swing");
        // 设置窗口大小
        f.setSize(400, 300);
        // 主窗口设置位置
        f.setLocation(200, 200);
        // 设置为绝对定位
        f.setLayout(null);
        // 按钮组件
        JButton b = new JButton("Hello");
        // 设置按钮大小和位置
        b.setBounds(50, 50, 280, 30);
        // 添加按钮到主窗口
        f.add(b);
        // 设置主窗口关闭时的操作
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // 显示主窗口
        f.setVisible(true);
    }

除了Jframe, Swing 还提供了 JDialog 作为容器:

public static void main(String[] args) {
        // using JDialog to create a window
        javax.swing.JDialog d = new javax.swing.JDialog();
        // set window title
        d.setTitle("Hello JDialog");
        // set window size
        d.setSize(400, 300);
        // set window location
        d.setLocation(200, 200);
        // set window layout
        d.setLayout(null);
        // set window visible
        d.setVisible(true);
    }

1.4 Swing 布局

Swing 的布局由布局器提供,布局器常见的布局有:

  • FlowLayout 顺序布局
  • BorderLayout 上下左右中间的顺序布局
  • GirdLayout 网格布局器
  • CardLayout 面板

举个例子,我们做个计算器:

public class Calculator extends JFrame implements ActionListener {

    private JTextField displayField;

    public Calculator() {
        setTitle("Calculator");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        // 创建显示区域
        displayField = new JTextField();
        displayField.setEditable(false);
        add(displayField, BorderLayout.NORTH);

        // 创建按钮面板
        JPanel buttonPanel = new JPanel(new GridLayout(4, 4));

        String[] buttonLabels = {
                "7", "8", "9", "/",
                "4", "5", "6", "*",
                "1", "2", "3", "-",
                "0", ".", "=", "+"
        };

        for (String label : buttonLabels) {
            JButton button = new JButton(label);
            button.addActionListener(this);
            buttonPanel.add(button);
        }

        add(buttonPanel, BorderLayout.CENTER);

        pack();
        setLocationRelativeTo(null); // 居中显示
    }

    public void actionPerformed(ActionEvent e) {
        String command = e.getActionCommand();
        String currentText = displayField.getText();

        if (command.equals("=")) {
            // 计算结果
            try {
                double result = evaluateExpression(currentText);
                displayField.setText(Double.toString(result));
            } catch (Exception ex) {
                displayField.setText("Error");
            }
        } else {
            // 在当前文本后追加按钮上的标签
            displayField.setText(currentText + command);
        }
    }

    private double evaluateExpression(String expression) {
        // 使用适当的算法计算表达式的结果
        // 这里仅为示例,可以使用自己的实现或相关库来计算表达式
        return new Object() {
            int pos = -1, ch;

            void nextChar() {
                ch = (++pos < expression.length()) ? expression.charAt(pos) : -1;
            }

            boolean eat(int charToEat) {
                while (ch == ' ') nextChar();
                if (ch == charToEat) {
                    nextChar();
                    return true;
                }
                return false;
            }

            double parse() {
                nextChar();
                double x = parseExpression();
                if (pos < expression.length()) throw new RuntimeException("Unexpected: " + (char) ch);
                return x;
            }

            double parseExpression() {
                double x = parseTerm();
                for (;;) {
                    if (eat('+')) x += parseTerm(); // 加法
                    else if (eat('-')) x -= parseTerm(); // 减法
                    else return x;
                }
            }

            double parseTerm() {
                double x = parseFactor();
                for (;;) {
                    if (eat('*')) x *= parseFactor(); // 乘法
                    else if (eat('/')) x /= parseFactor(); // 除法
                    else return x;
                }
            }

            double parseFactor() {
                if (eat('+')) return parseFactor(); // 正号
                if (eat('-')) return -parseFactor(); // 负号

                double x;
                int startPos = this.pos;
                if (eat('(')) { // 括号
                    x = parseExpression();
                    eat(')');
                } else if ((ch >= '0' && ch <= '9') || ch == '.') { // 数字
                    while ((ch >= '0' && ch <= '9') || ch == '.') nextChar();
                    x = Double.parseDouble(expression.substring(startPos, this.pos));
                } else {
                    throw new RuntimeException("Unexpected: " + (char) ch);
                }

                return x;
            }
        }.parse();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            Calculator calculator = new Calculator();
            calculator.setVisible(true);
        });
    }
}

这个计算器使用了BorderLayout布局管理器来实现

1.5 Swing 组件

Swing 提供了丰富的 GUI 组件,包括按钮、标签、文本框、复选框、单选框、下拉框、列表、表格等等。通过使用这些组件,我们可以构建出功能丰富的用户界面。

例如,下面是一个使用表格组件的示例代码,展示如何创建一个简单的表格并填充数据:

import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class TableExample extends JFrame {

    private JTable table;

    public TableExample() {
        setTitle("Table Example");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 创建表格模型和表格
        DefaultTableModel model = new DefaultTableModel();
        model.addColumn("Name");
        model.addColumn("Age");
        model.addRow(new Object[]{"Alice", 25});
        model.addRow(new Object[]{"Bob", 30});
        table = new JTable(model);

        // 将表格放置在滚动面板中
        JScrollPane scrollPane = new JScrollPane(table);

        // 将滚动面板添加到窗口中
        getContentPane().add(scrollPane);

        pack();
        setLocationRelativeTo(null); // 居中显示
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            TableExample frame = new TableExample();
            frame.setVisible(true);
        });
    }
}

2. 总结与补充

以上介绍了 Java Swing 的基本知识点,包括创建窗口、使用布局管理器、使用组件、注册监听器等。由于Java Swing 已 被淘汰,且调用 Swing 也仅仅是直接拿来用,并不涉及更多的开发思想,目前这部分技术已成历史,成为了我们选学的部分。当然,当今依然有很多高校在教Java Swing,其目的更多地是利用这个曾经占有一定市场份额的GUI技术带同学们入门,以及应付考试。

如果你对 Java Swing 很感兴趣,想单纯地用 Swing 实现自己的桌面应用,那么可以自行查阅支持 Swing 的 JDK API 文档。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值