JavaGUI——Java圖形使用者介面

靜守己心&笑淡浮華 發表於 2022-06-22
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);
    }
}