JavaGUI——Java图形用户界面

1、Java GUI 概述

GUI(Graphical User Interface,简称 GUI,图形用户界面)是指采用图形方式显示的计算机操作用户界面,与早期计算机使用的命令行界面相比,图形界面对于用户来说在视觉上更易于接受。
Java GUI主要有两个核心库,分别是AWT(java.awt:Abstract Windows ToolKit(抽象窗口工具包))和Swing(javax.swing:AWT的扩展),AWT需要调用本地系统方法来实现功能,属重量级控件,而Swing是在AWT的基础上,建立的一套图像界面系统,其中提供了更多的组件,而且完全由Java实现,增强了移植性,属轻量级组件。

2、容器

容器(Container)是组件(Component)的子类,一个容器可以容纳多个组件,并使他们成为一个整体。容器可以简化图形化界面的设计,以整体结构来布置界面,所有的组件都可以通过add()方法加入容器中。容器共有四种类型,分别是窗口(JFrame)、弹窗(JDialog)、面板(JPanel)、滚动面板(JScrollPanel)。

2、1 窗口

Frame或JFrame类用于创建一个具有标题栏的框架窗口作为程序的主要界面,它不依赖其他容器可以单独存在。

public class JFrameUse {
    public static void main(String[] args) {
        // 初始化窗口
        JFrame jFrame = new JFrame("这个是窗口的标题");
        // 设置窗口的位置和大小
        jFrame.setBounds(400, 300, 500, 500);
        // 设置窗口的背景颜色
        jFrame.setBackground(new Color(175, 114, 114));
        // 设置窗口是否可见
        jFrame.setVisible(true);
        // 设置窗口是否可以缩放
        jFrame.setResizable(false);
        /**
         * 设置窗口的相对位置。
         * 如果 comp 整个显示区域在屏幕内, 则将窗口放置到 comp 的中心;
         * 如果 comp 显示区域有部分不在屏幕内, 则将该窗口放置在最接近 comp 中心的一侧;
         * comp 为 null, 表示将窗口放置到屏幕中心。
         */
        jFrame.setLocationRelativeTo(null);
        /**
         * 设置窗口关闭按钮点击后的默认操作, 参考值:
         *     WindowConstants.DO_NOTHING_ON_CLOSE: 不执行任何操作。
         *     WindowConstants.HIDE_ON_CLOSE: 隐藏窗口(不会结束进程), 再次调用 setVisible(true) 将再次显示。
         *     WindowConstants.DISPOSE_ON_CLOSE: 销毁窗口, 如果所有可显示的窗口都被 DISPOSE, 则可能会自动结束进程。
         *     WindowConstants.EXIT_ON_CLOSE: 退出进程。
         */
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}

2、2 弹窗和对话框

JDialog,对话框,使用 JDialog 类可以创建自定义有的对话框,或者调用 JOptionPane 中的多个静态方法快速创建各种标准的对话框。
JOptionPane是JavaSwing内部已实现好的,以静态方法的形式提供调用,能够快速方便的弹出要求用户提供值或向其发出通知的标准对话框。主要具有以下几种那类型:

  • showMessageDialog:消息对话框,向用户展示一个消息,没有返回值。
  • showConfirmDialog:确认对话框,询问一个问题是否执行。
  • showInputDialog:输入对话框,要求用户提供某些输入。
  • showOptionDialog:选项对话框,上述三项的大统一,自定义按钮文本,询问用户需要点击哪个按钮。

上述四个类型的方法(包括其若干重载)的参数遵循一致的模式,下面介绍各参数的含义:

  • parentComponent: 对话框的父级组件,决定对话框显示的位置,对话框的显示会尽量紧靠组件的中心,如果传 null,则显示在屏幕的中心。
  • title: 对话框标题。
  • message: 消息内容。
  • optionType: 选项按钮的类型。
  • selectionValues、initialSelectionValue: 提供的输入选项,以及默认选中的选项。
  • icon: 自定义的对话框图标,如果传 null,则图标类型由 messageType 决定。
  • messageType: 消息类型,主要是提供默认的对话框图标。可能的值为:
    • JOptionPane.PLAIN_MESSAGE 简单消息(不使用图标)
    • JOptionPane.INFORMATION_MESSAGE 信息消息(默认)
    • JOptionPane.QUESTION_MESSAGE 问题消息
    • JOptionPane.WARNING_MESSAGE 警告消息
    • JOptionPane.ERROR_MESSAGE 错误消息

对话框

class JOptionPaneUse {
    public JOptionPaneUse() {
        final JFrame jf = new JFrame("测试窗口");
        jf.setSize(400, 400);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        /*
         * 1. 消息对话框(信息消息)
         */
        JButton btn01 = new JButton("showMessageDialog(信息消息)");
        btn01.addActionListener(e -> {
            // 消息对话框无返回, 仅做通知作用
            JOptionPane.showMessageDialog(jf, "通知信息", "消息标题", JOptionPane.INFORMATION_MESSAGE
            );
        });

        /*
         * 2. 消息对话框(警告消息)
         */
        JButton btn02 = new JButton("showMessageDialog(警告消息)");
        btn02.addActionListener(e -> {
            // 消息对话框无返回, 仅做通知作用
            JOptionPane.showMessageDialog(jf, "警告信息", "消息标题", JOptionPane.WARNING_MESSAGE);
        });

        /*
         * 3. 确认对话框
         */
        JButton btn03 = new JButton("showConfirmDialog");
        btn03.addActionListener(e -> {
            /*
             * 返回用户点击的选项, 值为下面三者之一:
             *     是:   JOptionPane.YES_OPTION
             *     否:   JOptionPane.NO_OPTION
             *     取消: JOptionPane.CANCEL_OPTION
             *     关闭: JOptionPane.CLOSED_OPTION
             */
            int result = JOptionPane.showConfirmDialog(jf, "确认删除?", "提示", JOptionPane.YES_NO_CANCEL_OPTION);
            System.out.println("选择结果: " + result);
        });

        /*
         * 4. 输入对话框(文本框输入)
         */
        JButton btn04 = new JButton("showInputDialog(文本框输入)");
        btn04.addActionListener(e -> {
            // 显示输入对话框, 返回输入的内容
            String inputContent = JOptionPane.showInputDialog(jf, "输入你的名字:", "默认内容");
            System.out.println("输入的内容: " + inputContent);
        });

        /*
         * 5. 输入对话框(下拉框选择)
         */
        JButton btn05 = new JButton("showInputDialog(下拉框选择)");
        btn05.addActionListener(e -> {
            Object[] selectionValues = new Object[]{"香蕉", "雪梨", "苹果"};
            // 显示输入对话框, 返回选择的内容, 点击取消或关闭, 则返回null
            Object inputContent = JOptionPane.showInputDialog(jf, "选择一项: ", "标题",
                    JOptionPane.PLAIN_MESSAGE, null, selectionValues, selectionValues[0]);
            System.out.println("输入的内容: " + inputContent);
        });

        /*
         * 6. 选项对话框
         */
        JButton btn06 = new JButton("showOptionDialog");
        btn06.addActionListener(e -> {
            // 选项按钮
            Object[] options = new Object[]{"香蕉", "雪梨", "苹果"};
            // 显示选项对话框, 返回选择的选项索引, 点击关闭按钮返回-1
            int optionSelected = JOptionPane.showOptionDialog(jf, "请点击一个按钮选择一项", "对话框标题",
                    JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE, null,
                    options,    // 如果传null, 则按钮为 optionType 类型所表示的按钮(也就是确认对话框)
                    options[0]
            );
            if (optionSelected >= 0) {
                System.out.println("点击的按钮: " + options[optionSelected]);
            }
        });

        // 垂直排列按钮
        Box vBox = Box.createVerticalBox();
        vBox.add(btn01);
        vBox.add(btn02);
        vBox.add(btn03);
        vBox.add(btn04);
        vBox.add(btn05);
        vBox.add(btn06);

        JPanel panel = new JPanel();
        panel.add(vBox);

        jf.setContentPane(panel);
        jf.setVisible(true);
    }
}

自定义弹窗

class JDialogUse {
    public JDialogUse() {
        final JFrame jf = new JFrame("测试窗口");
        jf.setSize(300, 300);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        JButton btn = new JButton("显示自定义对话框");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                showCustomDialog(jf, jf);
            }
        });

        JPanel panel = new JPanel();
        panel.add(btn);

        jf.setContentPane(panel);
        jf.setVisible(true);
    }

    /**
     * 显示一个自定义的对话框
     *
     * @param owner           对话框的拥有者
     * @param parentComponent 对话框的父级组件
     */
    private static void showCustomDialog(Frame owner, Component parentComponent) {
        // 创建一个模态对话框
        final JDialog dialog = new JDialog(owner, "提示", true);
        // 设置对话框的宽高
        dialog.setSize(250, 150);
        // 设置对话框大小不可改变
        dialog.setResizable(false);
        // 设置对话框相对显示的位置
        dialog.setLocationRelativeTo(parentComponent);

        // 创建一个标签显示消息内容
        JLabel messageLabel = new JLabel("对话框消息内容");

        // 创建一个按钮用于关闭对话框
        JButton okBtn = new JButton("确定");
        okBtn.addActionListener(e -> {
            // 关闭对话框
            dialog.dispose();
        });

        // 创建对话框的内容面板, 在面板内可以根据自己的需要添加任何组件并做任意是布局
        JPanel panel = new JPanel();

        // 添加组件到面板
        panel.add(messageLabel);
        panel.add(okBtn);

        // 设置对话框的内容面板
        dialog.setContentPane(panel);
        // 显示对话框
        dialog.setVisible(true);
    }
}

2、3 面板

面板也是一个容器,但是它不能单独存在,只能存在于窗口中,一个面板对象代表了一个长方形的区域,在这个区域中可以容纳其他组件,在程序中通常会使面板来实现一些特殊的布局。

普通面板

public class JPanelUse {
    public static void main(String[] args) {
        // 初始化窗口
        JFrame jFrame = new JFrame("面板窗口");
        jFrame.setVisible(true);
        jFrame.setSize(400, 400);
        jFrame.setLocationRelativeTo(null);
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        
        // 初始化面板:采用默认的流式布局或指定布局
        JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        // 设置面板大小
        jPanel.setSize(100, 100);
        // 设置面板背景颜色
        jPanel.setBackground(new Color(164, 24, 24));
        // 将面板添加到窗口
        jFrame.add(jPanel);
    }
}

滚动面板

JScrollPane,滚动面板,支持水平和垂直滚动视图。文本区域、表格等需要显示较多数据而空间又有限时,通常使用 JScrollPane 进行包裹以实现滚动显示。

public class JScrollPaneUse {
    public JScrollPaneUse() {
        JFrame jFrame = new JFrame("面板窗口");

        // 创建文本区域组件
        JTextArea textArea = new JTextArea("这是一个文本");
        // 自动换行
        textArea.setLineWrap(true);
        // 设置字体
        textArea.setFont(new Font(null, Font.PLAIN, 18));

        // 初始化滚动面板面板
        /**
         * 全参构造参数说明:
         *     view: 需要滚动显示的视图组件
         *     vsbPolicy: 垂直滚动条的显示策略
         *         ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED    // 需要时显示(默认)
         *         ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER        // 从不显示
         *         ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS       // 总是显示
         *     hsbPolicy: 水平滚动条的显示策略
         *         ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED  // 需要时显示(默认)
         *         ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER      // 从不显示
         *         ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS     // 总是显示
         * 常用方法
         *     设置滚动显示视图内容组件:setViewportView(Component view)
         *     设置垂直滚动条的显示策略:setVerticalScrollBarPolicy(int policy)
         *     设置水平滚动条的显示策略:setHorizontalScrollBarPolicy(int policy)
         */
        JScrollPane jScrollPane = new JScrollPane(
                textArea,
                ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
        );
        jFrame.setContentPane(jScrollPane);

        // 窗口设置为公共代码,后面全部省略
        jFrame.setVisible(true);
        jFrame.setSize(400, 400);
        jFrame.setLocationRelativeTo(null);
        jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}

分隔面板

JSplitPane,分隔面板,用于分隔两个(只能两个)组件,两个组件通过水平/垂直分隔条分别 左右 或 上下 显示,并且可以拖动分隔条调整两个组件显示区域的大小。

class JSplitPaneUse{
    public JSplitPaneUse() {
        JFrame jFrame = new JFrame("分隔面板窗口");

        /**
         * 全参构造参数说明
         *      orientation: 分隔的方向(默认水平),HORIZONTAL_SPLIT:水平左右分隔;VERTICAL_SPLIT:垂直上下分隔
         *      continuousLayout: 拖动分隔条时,是否连续重绘组件,如果为flase,则拖动分隔条停止后才重绘组件。
         *      leftComponent: 左边/上面 显示的组件
         *      rightComponent: 右边/下面 显示的组件
         * 常用方法
         *    setOrientation(int orientation): 设置分隔的方向,水平(左右) 或 垂直(上下) 分隔
         *    setLeftComponent(Component comp):设置 左边/上面 显示的组件
         *    setRightComponent(Component comp):设置 左边/下面 显示的组件
         *    setContinuousLayout(boolean continuousLayout): 设置 拖动分隔条 时是否 连续重绘 组件
         *    setOneTouchExpandable(boolean newValue):分隔条上是否显示快速 折叠/展开 两边组件的小按钮
         *    setDividerSize(int newSize):设置分隔条的大小(宽度)
         *    setDividerLocation(int location):设置分隔条的位置,相对于 左边/顶部 的像素长度
         */
        JSplitPane jSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, new JButton("左边按钮"), new JButton("右边按钮"));
        jSplitPane.setDividerLocation(200);

        jFrame.setContentPane(jSplitPane);
        // 省略公共代码
    }
}

选项卡面板

JTabbedPane,选项卡面板。它允许用户通过点击给定标题或图标的选项卡,在一组组件之间进行切换显示。

class JTabbedPaneUse {
    public JTabbedPaneUse() {
        JFrame jFrame = new JFrame("选项卡面板窗口");

        /**
         * 全参构造参数说明:
         *     tabPlacement: 选项卡标题的位置, 值为 JTabbedPane.TOP/BOTTOM/LEFT/RIGHT, 默认为 TOP
         *     tabLayoutPolicy: 选项卡位置不能放入所有的选项卡时,放置选项卡的策略,值JTabbedPane.WRAP_TAB_LAYOUT/SCROLL_TAB_LAYOUT
         * 常用方法
         *     addTab(String 标题, Icon 图标, Component 内容组件, String 提示文本):添加选择项卡
         *     insertTab(String title, Icon icon, Component component, String tip, int index):在指定位置插入选项卡
         *     remove(Component component):移除指定内容控件的选项卡
         *     remove(int index):移除指定位置的选项
         *     setSelectedIndex(int index):设置当前选中的选项卡
         *     getSelectedIndex():获取当前选中的选项卡索引
         *     getSelectedComponent():获取当前选中的选项卡对应的内容组件
         *     setTitleAt(int index, String title):设置 index 位置的选项卡的标题
         *     setIconAt(int index, Icon icon):设置 index 位置的选项卡的图标
         *     setEnabledAt(int index, boolean enabled):设置 index 位置的选项卡是否可用
         *     setComponentAt(int index, Component component):将 index 位置的内容组件设置为 component
         */
        // 初始化一个选项面板,默认选项卡在顶部,放不下了换行
        JTabbedPane jTabbedPane = new JTabbedPane(JTabbedPane.TOP, JTabbedPane.WRAP_TAB_LAYOUT);

        // 创建选项卡
        jTabbedPane.addTab("选项卡1", new JButton("测试按钮"));
        jTabbedPane.addTab("选项卡2", new JButton("测试按钮"));
        jFrame.setContentPane(jTabbedPane);

        // 省略公共代码
    }
}

3、布局

3.1、流式布局

FlowLayout,流式布局管理器,按水平方向依次排列放置组件,排满一行,换下一行继续排列。排列方向(左到右 或 右到左)取决于容器的componentOrientation属性(该属性属于Component),它可能的值如下:

  • ComponentOrientation.LEFT_TO_RIGHT(默认)
  • ComponentOrientation.RIGHT_TO_LEFT

同一行(水平方向)的组件的对齐方式由 FlowLayout 的align属性确定,它可能的值如下:

  • FlowLayout.LEFT : 左对齐
  • FlowLayout.CENTER : 居中对齐(默认)
  • FlowLayout.RIGHT : 右对齐
  • FlowLayout.LEADING : 与容器方向的开始边对齐,例如,对于从左到右的方向,则与左边对齐
  • FlowLayout.TRAILING : 与容器方向的结束边对齐,例如,对于从左到右的方向,则与右边对齐。
class FlowLayoutUse {
    public FlowLayoutUse() {
        JFrame jFrame = new JFrame("流式布局窗口");

        // 创建面板并指定为流式布局
        JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        // 创建两个按钮
        JButton jButton1 = new JButton("按钮1");
        JButton jButton2 = new JButton("按钮2");
        // 将按钮添加到面板中
        jPanel.add(jButton1);
        jPanel.add(jButton2);
        // 将面板添加到窗口中
        jFrame.setContentPane(jPanel);

        // 省略公共代码
    }
}

3.2、网格布局

GridLayout,网格布局管理器,它以矩形网格形式对容器的组件进行布置,把容器按行列分成大小相等的矩形网格,一个网格中放置一个组件,组件宽高自动撑满网格。
以行数和总数优先: 通过构造方法或 setRows 和 setColumns 方法将行数和列数都设置为非零值时,指定的列数将被忽略。列数通过指定的行数和布局中的组件总数来确定。因此,例如,如果指定了三行和两列,在布局中添加了九个组件,则它们将显示为三行三列。仅当将行数设置为零时,指定列数才对布局有效。

class GridLayoutUse {
    public GridLayoutUse() {
        JFrame jFrame = new JFrame("网格布局窗口");

        // 创建一个面板并使用网格布局
        JPanel jPanel = new JPanel(new GridLayout(2, 2));
        // 创建五个按钮,测试2行2列超出效果
        JButton jButton1 = new JButton("按钮1");
        JButton jButton2 = new JButton("按钮2");
        JButton jButton3 = new JButton("按钮3");
        JButton jButton4 = new JButton("按钮4");
        JButton jButton5 = new JButton("按钮5");
        jPanel.add(jButton1);
        jPanel.add(jButton2);
        jPanel.add(jButton3);
        jPanel.add(jButton4);
        jPanel.add(jButton5);
        jFrame.setContentPane(jPanel);

        // 省略公共代码
    }
}

3.3、边框布局

BorderLayout,边界布局管理器,它把 Container 按方位分为 5 个区域(东、西、南、北、中),每个区域放置一个组件。

class BorderLayoutUse {
    public BorderLayoutUse() {
        JFrame jFrame = new JFrame("网格布局窗口");

        // 创建一个面板并使用边框布局
        JPanel jPanel = new JPanel(new BorderLayout());
        // 创建五个按钮,测试2行2列超出效果
        JButton jButton1 = new JButton("东");
        JButton jButton2 = new JButton("西");
        JButton jButton3 = new JButton("南");
        JButton jButton4 = new JButton("北");
        JButton jButton5 = new JButton("中");
        jPanel.add(jButton1, BorderLayout.EAST);
        jPanel.add(jButton2, BorderLayout.WEST);
        jPanel.add(jButton3, BorderLayout.SOUTH);
        jPanel.add(jButton4, BorderLayout.NORTH);
        jPanel.add(jButton5, BorderLayout.CENTER);
        jFrame.setContentPane(jPanel);

        // 省略公共代码
    }
}

4、组件

4.1、基本组件

标签

JLabel,标签,主要用于展示文本图片,也可以同时显示文本和图片。

class JLabelUse {
    public JLabelUse() {
        JFrame jFrame = new JFrame("标签窗口");
        JPanel jPanel = new JPanel();

        // 只显示文本的标签
        JLabel textLabel = new JLabel("只显示文本的标签");
        textLabel.setFont(new Font(null, Font.PLAIN, 25));
        jPanel.add(textLabel);

        // 只显示图片的标签
        JLabel imgLabel = new JLabel(new ImageIcon("bj.jpg"));
        jPanel.add(imgLabel);

        // 同时显示文本和图片的标签:水平方向文本在图片中心
        JLabel jLabel = new JLabel("显示文本", new ImageIcon("bj.jpg"), SwingConstants.CENTER);
        jPanel.add(jLabel);
		
        jFrame.setContentPane(jPanel);
        // 省略公共代码
    }
}

按钮

class JButtonAndRadioAndCheckBox {
    public JButtonAndRadioAndCheckBox() {
        JFrame jFrame = new JFrame("标签窗口");
        JPanel jPanel = new JPanel();

        /**
         * 普通图片按钮
         */
        JButton jButton = new JButton("图片按钮", new ImageIcon("bj.jpg"));
        jButton.addActionListener(e -> {
            System.out.println("图片按钮被点击了");
        });
        jPanel.add(jButton);

        /**
         * 单选按钮
         */
        // 创建按钮组,将单选按钮添加到该组,确保只能选择其一
        ButtonGroup buttonGroup = new ButtonGroup();
        // 创建单选按钮
        JRadioButton man = new JRadioButton("男");
        JRadioButton woman = new JRadioButton("女");
        // 设置第一个被选中
        man.setSelected(true);
        // 将按钮添加到按钮组中
        buttonGroup.add(man);
        buttonGroup.add(woman);
        // 将按钮添加到面板中
        jPanel.add(man);
        jPanel.add(woman);

        /**
         * 多选按钮
         */
        // 添加多选按钮
        JCheckBox jCheckBox1 = new JCheckBox("香蕉");
        JCheckBox jCheckBox2 = new JCheckBox("苹果");
        JCheckBox jCheckBox3 = new JCheckBox("梨子");
        JCheckBox jCheckBox4 = new JCheckBox("黄瓜");
        // 添加事件监听,添加第一个复选框的状态被改变的监听(其他复选框如果需要监听状态改变,则可按此方法添加监听)
        jCheckBox1.addChangeListener(e -> {
            // 获取事件源(即复选框本身)
            JCheckBox jCheckBox = (JCheckBox) e.getSource();
            System.out.println(jCheckBox.getText() + " 是否选中: " + jCheckBox.isSelected());
        });
        jCheckBox1.setSelected(true);
        jPanel.add(jCheckBox1);
        jPanel.add(jCheckBox2);
        jPanel.add(jCheckBox3);
        jPanel.add(jCheckBox4);


        jFrame.setContentPane(jPanel);
       // 省略公共代码
    }
}

列表

JComboBox,下拉框。JComboBox以下列列表的形式展示多个选项,用户可以从下拉列表中选择一个值。如果设置JComboBox为可编辑状态,除了选择指定的选项值外,还允许用户自行输入值(自行输入的值索引为-1)。

JList,列表框。JList 以列表的形式展示多个选项,允许用户选择一个或多个选项。其中的选项内容由一个 ListModel 实例来维护。JList 不实现直接滚动,需要滚动显示,可以结合 JScrollPane 实现滚动效果。

class JComboBoxAndJList {
    public JComboBoxAndJList() {
        JFrame jFrame = new JFrame("列表窗口");
        JPanel jPanel = new JPanel();
        JLabel jLabel = new JLabel("水果");

        /**
         * 下拉框:这里的数组列表可以使用Vector<String>集合进行
         */
        final JComboBox<String> jComboBox = new JComboBox<>(new String[]{"香蕉", "雪梨", "苹果", "荔枝"});
        // 添加条目选中状态改变的监听器
        jComboBox.addItemListener(e -> {
            // 只处理选中的状态
            if (e.getStateChange() == ItemEvent.SELECTED) {
                System.out.println("选中: " + jComboBox.getSelectedIndex() + " = " + jComboBox.getSelectedItem());
            }
        });
        jPanel.add(jLabel);
        jPanel.add(jComboBox);

        /**
         * 列表框
         */
        final JList<String> jList = new JList<>();
        // 设置一下首选大小
        jList.setPreferredSize(new Dimension(200, 100));
        // 允许可间断的多选
        jList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        // 设置选项数据(内部将自动封装成 ListModel ),这里的数组列表可以使用Vector<String>集合进行
        jList.setListData(new String[]{"香蕉", "雪梨", "苹果", "荔枝"});
        // 添加选项选中状态被改变的监听器
        jList.addListSelectionListener(e -> {
            // 获取所有被选中的选项索引
            int[] indices = jList.getSelectedIndices();
            // 获取选项数据的 ListModel
            ListModel<String> listModel = jList.getModel();
            // 输出选中的选项
            for (int index : indices) {
                System.out.println("选中: " + index + " = " + listModel.getElementAt(index));
            }
            System.out.println();
        });
        jPanel.add(jList);

        jFrame.setContentPane(jPanel);
      // 省略公共代码
    }
}

文本框

JTextField,文本框。JTextField 用来编辑单行的文本。

JPasswordField,密码框。JPasswordField 继承自 JTextField,只是显示输入的内容时用特定的字符替换显示(例如 * 或 ●),用法和 JTextField 基本一致。

JTextArea,文本区域。JTextArea 用来编辑多行的文本。JTextArea 除了允许多行编辑外,其他基本用法和 JTextField 基本一致。

class JTextFieldAndJPasswordFieldAndJTextAreaUse {
    public JTextFieldAndJPasswordFieldAndJTextAreaUse() {
        JFrame jFrame = new JFrame("列表窗口");
        JPanel jPanel = new JPanel(new GridLayout(3,1));

        /**
         * 文本框
         */
        final JTextField jTextField = new JTextField(10);
        jTextField.setFont(new Font(null, Font.PLAIN, 20));
        jPanel.add(new JLabel("用户名"));
        jPanel.add(jTextField);

        /**
         * 密码框
         */
        final JPasswordField jPasswordField = new JPasswordField(32);
        jPanel.add(new JLabel("密 码"));
        jPanel.add(jPasswordField);

        /**
         * 文本域
         */
        // 创建一个 5 行 10 列的文本区域
        JTextArea jTextArea = new JTextArea(5, 10);
        // 自动换行
        jTextArea.setLineWrap(true);
        jPanel.add(new JLabel("文本域"));
        jPanel.add(jTextArea);

        jFrame.setContentPane(jPanel);
        // 省略公共代码
    }
}

进度条和滑块

JProgressBar,进度条。以可视化形式显示某些任务进度的组件,进度条中心可显示进度百分比的文本表示形式。一个任务的进度长度未知时,可将进度条设置为不确定模式。不确定模式的进度条持续地显示动画来表示正进行的操作。当可以确定任务长度和进度量时,则可设置进度条的最大最小值,以及更新进度条的进度值,将其切换回确定模式。

JSlider,滑块。以图形方式在有界区间内通过移动滑块来选择值的组件。滑块可以显示主刻度标记以及主刻度之间的次刻度标记。刻度标记之间的值的个数由 setMajorTickSpacing(int) 和 setMinorTickSpacing(int) 来控制。刻度标记的绘制由 setPaintTicks(boolean) 控制。滑块也可以在固定时间间隔(或在任意位置)沿滑块刻度打印文本标签。标签的绘制由 setLabelTable(Dictionary) 和 setPaintLabels(boolean) 控制。
PS: 当滑块获得焦点后,按键盘上的 上下左右键 也可以滑动滑块。

class JProgressBarAndJSliderUse {
    public JProgressBarAndJSliderUse() {
        JFrame jFrame = new JFrame("列表窗口");
        JPanel jPanel = new JPanel(new GridLayout(3, 1));

        /**
         * 进度条:
         *     全参构造参数说明:JProgressBar(int orient, int min, int max)
         *         orient: 进度条的方向,SwingConstants.VERTICAL 或 SwingConstants.HORIZONTAL,默认为水平方向
         *         min: 最小进度值;max: 最大进度值
         *     常用方法:
         *         设置最小进度值、最大进度值和当前进度值:setMinimum(int min),setMaximum(int max),setValue(int n)
         *         获取当前进度值:getValue()
         *         获取当前进度的百分比:getPercentComplete()
         *         是否绘制百分比文本(进度条中间显示的百分数):setStringPainted(boolean b)
         *         设置进度条进度是否为不确定模式:setIndeterminate(boolean newValue)
         *         设置进度条的方向,SwingConstants.VERTICAL 或 SwingConstants.HORIZONTAL:setOrientation(int newOrientation)
         *         添加进度条的进度改变监听器:addChangeListener(ChangeListener l)
         */
        JProgressBar jProgressBar = new JProgressBar(0, 100);
        jProgressBar.setValue(20);
        jProgressBar.addChangeListener(e -> {
            System.out.println("当前进度值: " + jProgressBar.getValue() + "; " +
                    "进度百分比: " + jProgressBar.getPercentComplete());
        });
        jPanel.add(jProgressBar);

        /**
         * 滑块:
         *     全参构造参数说明:JSlider(int orientation, int min, int max, int value)
         *         orientation: 滑块的方向,SwingConstants.VERTICAL 或 SwingConstants.HORIZONTAL,默认为水平方向
         *         min: 滑块的最小值; max: 滑块的最大值
         *         value: 滑块的初始值(默认为 最小值 和 最大值 之间的 中间值)
         *     常用方法:
         *         设置滑块的最小值、最大值、当前值:setMinimum(int min),setMaximum(int max),setValue(int n)
         *         获取滑块的当前值:getValue()
         *         设置主刻度标记间隔:setMajorTickSpacing(int n)
         *         设置单个主刻度内的次刻度标记间隔:setMinorTickSpacing(int n)
         *         设置是否绘制刻度线:setPaintTicks(boolean b)
         *         设置是否绘制刻度标签(刻度值文本):setPaintLabels(boolean b)
         *         设置是否绘制滑道:setPaintTrack(boolean b)
         *         设置是否颠倒刻度值(刻度值从大到小):setInverted(boolean b)
         *         设置滑块是否对齐到刻度。设置为 true,则滑块最终只能在有刻度的位置取值,即滑块取值不连续:setSnapToTicks(boolean b)
         *         添加滑块的值改变监听器:addChangeListener(ChangeListener l)
         */
        JSlider jSlider = new JSlider(0, 20, 10);
        // 设置主刻度间隔
        jSlider.setMajorTickSpacing(5);
        // 设置次刻度间隔
        jSlider.setMinorTickSpacing(1);
        // 绘制刻度和标签
        jSlider.setPaintTicks(true);
        jSlider.setPaintLabels(true);
        jSlider.addChangeListener(e -> {
            System.out.println("当前值: " + jSlider.getValue());
        });
        jPanel.add(jSlider);

        jFrame.setContentPane(jPanel);
        // 省略公共代码
    }
}

4.2、复杂组件

文件和颜色选择器

JFileChooser,文件选取器。JFileChooser为用户选择文件提供了一种简单的机制,包括打开文件和保存文件。
构造方法和常用方法如下:

方法 功能
JFileChooser(String currentDirectoryPath) currentDirectoryPath: 打开文件选取器时默认显示的文件夹(默认为用户文件夹)
JFileChooser(File currentDirectory) currentDirectory: 打开文件选取器时默认显示的文件夹(默认为用户文件夹)
void setCurrentDirectory(File dir) 设置默认显示的文件夹
void setFileSelectionMode(int mode) 设置文件选择模式,FILES_AND_DIRECTORIES: 文件和文件夹都可以选,其他的二选一
void setMultiSelectionEnabled(boolean b) 设置是否允许同时选择多个(默认为不允许)
void addChoosableFileFilter(FileFilter filter) 添加可供用户选择的文件过滤器
void setFileFilter(FileFilter filter) 设置默认使用的文件过滤器
void setSelectedFile(File file) 设置默认被选中的文件
File[] getSelectedFiles() 获取选择的文件(一般在用户选择完文件点击了确认或保存后通过该方法获取选中的文件)
class FileSelectedUse {
    public FileSelectedUse() {
        JFrame jFrame = new JFrame();
        JPanel jPanel = new JPanel();

        /**
         * 显示 打开文件 或 保存文件 的对话框(线程将被阻塞, 直到选择框被关闭):showOpenDialog(Component parent), showSaveDialog(Component parent)
         *     参数:
         *         parent: 文件选取器对话框的父组件, 对话框将会尽量显示在靠近 parent 的中心; 如果传 null, 则显示在屏幕中心。
         *     返回值:
         *         JFileChooser.CANCEL_OPTION: 点击了取消或关闭
         *         JFileChooser.APPROVE_OPTION: 点击了确认或保存
         *         JFileChooser.ERROR_OPTION: 出现错误
         */
        final JTextArea jTextArea = new JTextArea(10, 30);
        jTextArea.setLineWrap(true);
        jPanel.add(jTextArea);

        JButton openBtn = new JButton("打开");
        openBtn.addActionListener(e -> showFileOpenDialog(jFrame, jTextArea));
        jPanel.add(openBtn);

        JButton saveBtn = new JButton("保存");
        saveBtn.addActionListener(e -> showFileSaveDialog(jFrame, jTextArea));
        jPanel.add(saveBtn);

        jFrame.setContentPane(jPanel);
        // 省略公共代码
    }

    /**
     * 打开文件
     * @param parent 组件
     * @param msgTextArea 文本域
     */
    private static void showFileOpenDialog(Component parent, JTextArea msgTextArea) {
        // 创建一个默认的文件选取器
        JFileChooser fileChooser = new JFileChooser();
        // 设置默认显示的文件夹为当前文件夹
        fileChooser.setCurrentDirectory(new File("."));
        // 设置文件选择的模式(只选文件、只选文件夹、文件和文件均可选)
        fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        // 设置是否允许多选
        fileChooser.setMultiSelectionEnabled(true);
        // 添加可用的文件过滤器(FileNameExtensionFilter 的第一个参数是描述, 后面是需要过滤的文件扩展名 可变参数)
        fileChooser.addChoosableFileFilter(new FileNameExtensionFilter("zip(*.zip, *.rar)", "zip", "rar"));
        // 设置默认使用的文件过滤器
        fileChooser.setFileFilter(new FileNameExtensionFilter("image(*.jpg, *.png, *.gif)", "jpg", "png", "gif"));
        // 打开文件选择框(线程将被阻塞, 直到选择框被关闭)
        int result = fileChooser.showOpenDialog(parent);
        if (result == JFileChooser.APPROVE_OPTION) {
            // 如果点击了"确定", 则获取选择的文件路径
            File file = fileChooser.getSelectedFile();
            // 如果允许选择多个文件, 则通过下面方法获取选择的所有文件
            msgTextArea.append("打开文件: " + file.getAbsolutePath() + "\n\n");
        }
    }

    /**
     * 选择文件保存路径
     * @param parent 组件
     * @param msgTextArea 文本域
     */
    private static void showFileSaveDialog(Component parent, JTextArea msgTextArea) {
        // 创建一个默认的文件选取器
        JFileChooser fileChooser = new JFileChooser();
        // 设置打开文件选择框后默认输入的文件名
        fileChooser.setSelectedFile(new File("测试文件.zip"));
        // 打开文件选择框(线程将被阻塞, 直到选择框被关闭)
        int result = fileChooser.showSaveDialog(parent);
        if (result == JFileChooser.APPROVE_OPTION) {
            // 如果点击了"保存", 则获取选择的保存路径
            File file = fileChooser.getSelectedFile();
            msgTextArea.append("保存到文件: " + file.getAbsolutePath() + "\n\n");
        }
    }
}

JColorChooser,颜色选取器。JColorChooser提供一个用于允许用户操作和选择颜色的控制器对话框。

class ColorSelectedUse {
    public ColorSelectedUse() {
        JFrame jFrame = new JFrame();
        JPanel jPanel = new JPanel();
        final JLabel jLabel = new JLabel();
        jLabel.setPreferredSize(new Dimension(150, 150));
        jLabel.setOpaque(true);
        jPanel.add(jLabel);

        JButton jButton = new JButton("选择颜色");
        jButton.addActionListener(e -> {
            /**
             * 显示一个颜色选取器对话框(线程将被阻塞, 直到对话框被关闭)
             *     参数说明:
             *          component: 对话框的父组件, 对话框将紧靠 component 的中心显示; 如果传 null, 则对话框显示在屏幕中心。
             *          title: 对话框标题。
             *          initialColor: 初始选中的颜色; 如果传 null, 则默认为非透明白色。
             *      返回值:
             *          返回选择的颜色; 如果点击了取消或关闭, 则返回 null。
             */
            Color color = JColorChooser.showDialog(jFrame, "选取颜色", null);
            // 如果用户取消或关闭窗口, 则返回的 color 为 null
            if (color == null) {
                return;
            }
            // 把选取的颜色设置为标签的背景
            jLabel.setBackground(color);
            // 获取颜色的 ARGB 各个分量值
            int alpha = color.getAlpha();
            int red = color.getRed();
            int green = color.getGreen();
            int blue = color.getBlue();
            jLabel.setText("A=" + String.format("%02x", alpha) + ", " +
                    String.format("#%02x%02x%02x", red, green, blue));
        });
        jPanel.add(jButton);

        jFrame.setContentPane(jPanel);
        // 省略公共代码
    }
}

菜单栏和工具栏

JMenuBar,菜单栏。菜单栏组件添加到 JFrame 窗口后,在窗口的内容显示区域的顶部出现。实现一个菜单栏主要涉及三种类:

  • JMenuBar:表示一个菜单栏。
  • JMenu:表示菜单栏上的一个一级菜单。
  • JMenuItem, JCheckBoxMenuItem, JRadioButtonMenuItem:表示一级菜单下的一个子菜单项,三者分别表示 普通的子菜单、带复选框的子菜单、带单选按钮的子菜单。

PS: JMenu 继承自 JMenuItem,所以一个 JMenu 也可以当做是一个二级子菜单项,通过 JMenu 和 JMenuItem 之间的嵌套,可实现多级子菜单效果。
构造参数和常用方法如下

方法 功能
JMenuItem void setText(String text) 设置菜单显示的文本
JMenuItem void setIcon(Icon defaultIcon) 设置菜单显示的图标
全参构造 JMenuItem(String text, Icon icon) text: 菜单显示的文本,icon: 菜单显示的图标
JMenuItem void setMnemonic(int mnemonic) 设置菜单的键盘助记符
JMenuItem void setAccelerator(KeyStroke keyStroke) 设置修改键,使用键盘快捷键直接触发菜单项的动作
JMenuItem void addActionListener(ActionListener l) 添加菜单被点击的监听器
JMenuItem void setActionCommand(String actionCommand) 可以再监听器回调时通过命令名称区别是哪个菜单项触发的动作。
JMenu JMenuItem add(JMenuItem menuItem) 添加子菜单到JMenu中
JMenu void addSeparator() 添加一个子菜单分割线
class JMenuBarUse{
    public JMenuBarUse() {
        JFrame jFrame = new JFrame();
        JPanel jPanel = new JPanel();

        // 创建一个菜单栏
        JMenuBar jMenuBar = new JMenuBar();
        
        // 创建一级菜单
        JMenu fileMenu = new JMenu("文件");
        JMenu editMenu = new JMenu("编辑");
        // 将一级菜单添加到菜单栏
        jMenuBar.add(fileMenu);
        jMenuBar.add(editMenu);
        
        // 创建文件菜单的子菜单
        JMenuItem openMenuItem  = new JMenuItem("打开");
        JMenuItem newMenuItem  = new JMenuItem("新建");
        fileMenu.add(newMenuItem);
        fileMenu.add(openMenuItem);

        jPanel.add(jMenuBar);
        // 省略公共代码
    }
}

JToolBar,工具栏。JToolBar 提供了一个用来显示常用控件的容器组件。
对于大多数的外观,用户可以将工具栏拖到其父容器四“边”中的一边,并支持在单独的窗口中浮动显示。为了正确执行拖动,建议将 JToolBar 实例添加到容器四“边”中的一边(其中容器的布局管理器为 BorderLayout),并且不在其他四“边”中添加任何子级。
构造方法和常用方法如下:

方法 功能
JToolBar(String name, int orientation) name: 工具栏名称,悬浮显示时为悬浮窗口的标题。orientation: 工具栏方向,默认水平
Component add(Component comp) 添加 工具组件 到 工具栏
void addSeparator(Dimension size) 添加 分隔符组件 到 工具栏
Component getComponentAtIndex(int index) 获取工具栏中指定位置的组件(包括分隔符)
void setFloatable(boolean b) 设置工具栏是否可拖动
void setOrientation(int o) 设置工具栏方向,值为 SwingConstants.HORIZONTAL 或 SwingConstants.VERTICAL
void setMargin(Insets m) 设置工具栏边缘和其内部工具组件之间的边距(内边距)
void setBorderPainted(boolean b) 是否需要绘制边框
class JToolBarUse{
    public JToolBarUse() {
        JFrame jFrame = new JFrame();
        JPanel jPanel = new JPanel();

        // 创建一个工具栏
        JToolBar jToolBar = new JToolBar("测试工具栏");
        JButton jButton = new JButton("按钮");
        jToolBar.add(jButton);

        jPanel.add(jToolBar);
        // 省略公共代码
    }
}

5、事件

5.1、鼠标监听事件

class MouseListenerUse {
    public MouseListenerUse() {
        JFrame jFrame = new JFrame("鼠标监听");
        JPanel jPanel = new JPanel();

        /**
         * 鼠标监听器
         */
        jPanel.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                System.out.println("鼠标进入组件区域");
            }

            @Override
            public void mouseExited(MouseEvent e) {
                System.out.println("鼠标离开组建区域");
            }

            @Override
            public void mousePressed(MouseEvent e) {
                // 获取按下的坐标(相对于组件)
                System.out.println("相对组件" + e.getPoint() + ",横坐标:" + e.getX() + ", 纵坐标:" + e.getY());
                // 获取按下的坐标(相对于屏幕)
                System.out.println("相对屏幕" + e.getLocationOnScreen() + ",横坐标:" + e.getXOnScreen() + ", 纵坐标:" + e.getYOnScreen());
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                System.out.println("鼠标释放");
            }

            @Override
            public void mouseClicked(MouseEvent e) {
                // 鼠标在组件区域内按下并释放(中间没有移动光标)才识别为被点击
                System.out.println("鼠标点击");
            }
        });

        /**
         * 鼠标移动/拖动监听器
         */
        jPanel.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                // 鼠标保持按下状态移动即为拖动
                System.out.println("鼠标拖动");
            }
            @Override
            public void mouseMoved(MouseEvent e) {
                System.out.println("鼠标移动");
            }
        });


        /**
         * 鼠标滚轮监听器
         */
        jPanel.addMouseWheelListener(new MouseWheelListener() {
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                // e.getWheelRotation() 为滚轮滚动多少的度量
                System.out.println("mouseWheelMoved: " + e.getWheelRotation());
            }
        });

       // 省略公共代码
    }
}

5.2、键盘监听事件

组件监听键盘的按键,该组件必须要获取到焦点。

如果一个窗口内没有可获取焦点的组件,一般打开窗口后焦点为窗口所有,可以把键盘监听器设置到窗口(JFrame)身上。

如果窗口内还有其他组件可获取焦点(例如按钮、文本框),窗口打开后焦点会被内部组件获得,如果想要在窗口打开期间都能监听键盘按键,可以为所有可获得焦点的组件都设置一个键盘监听器。

class KeyListenerUse{
    public KeyListenerUse() {
        JFrame jFrame = new JFrame("键盘监听");
        jFrame.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                // 获取键值,和 KeyEvent.VK_XXXX 常量比较确定所按下的按键
                System.out.println("按下: " + e.getKeyCode() + ",键值为:" + e.getKeyCode());
            }

            @Override
            public void keyTyped(KeyEvent e) {
                // e.getKeyChar() 获取键入的字符
                System.out.println("键入: " + e.getKeyChar());
            }

            @Override
            public void keyReleased(KeyEvent e) {
                System.out.println("释放: " + e.getKeyCode());
            }
        });
        jFrame.setVisible(true);
    }
}

5.3、窗口监听事件

窗口监听器只有窗口类组件支持,例如 JFrame、JDialog。目前经过测试,使用最多的莫过于窗口关闭和窗口激活。

class WindowListenerUse{
    public WindowListenerUse() {
        JFrame jFrame = new JFrame("窗口监听");
        jFrame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("窗口被关闭了");
            }

            @Override
            public void windowActivated(WindowEvent e) {
                System.out.println("窗口被激活了");
            }
        });
        jFrame.setVisible(true);
    }
}
posted @ 2022-06-22 14:11  静守己心&笑淡浮华  阅读(2718)  评论(9编辑  收藏  举报