1. 程式人生 > 實用技巧 >Java GUI swing 工具包使用總結

Java GUI swing 工具包使用總結

前言

最近用 swing 寫了一個GUI圖片接入的工具, 方便用於將圖片資料通過介面推送到 web 專案中

做介面有點像寫原生的 CSS


技術儲備

  1. java

    基礎知識, 面向物件封裝, 繼承, 介面

    匿名內部類, Lambda

  2. 開發工具

    IDEA


功能需求

AI智檢

  1. 支援合成圖和序列圖

  2. 工具支援填寫資料地址,根據資料地址自動將資料快速匯入平臺

    資料為圖片,圖片資訊在圖片名稱上面,欄位資訊已特定的分隔符連線,各個現場不同

  3. 工具支援填寫客戶違法編碼

    如果填寫了違法編碼,則以填寫為準,否則以欄位對映關係切割為準

  4. 工具支援填寫合成圖模式

  5. 工具支援自動根據圖片名稱獲取圖片及相關資訊

  6. 工具支援自動匹配車牌根據設定規則

    如果填寫車牌匹配規則,以匹配為準,否則以欄位對映關係切割為準

  7. 工具支援預設資料補充

    平臺非必須欄位,程式指定預設值

  8. 平臺支援離線測試資料,快速看到演算法識別指標 (保持智檢測試看到的效果)

    • 資料匯入之後自動建立測試任務,操作人員登入平臺人工開啟任務

    • 任務名稱:工具接入_2020-07-04_12:22:30

  9. 支援匯入進度檢視

    • 匯入總量及百分比
    • 匯入成功數量及錯誤數量
  10. 支援檢視工具執行日誌

  11. 工具為windows exe格式


AI預審

  1. 支援合成圖和序列圖

  2. 工具支援填寫資料地址,根據資料地址自動將資料快速匯入平臺

    資料為圖片,圖片資訊在圖片名稱上面,欄位資訊已特定的分隔符連線,各個現場不同

  3. 工具支援自動根據圖片名稱獲取圖片及相關資訊

  4. 工具支援預設資料補充

    平臺非必須欄位,程式指定預設值

  5. 平臺支援離線測試資料,快速看到演算法識別指標(保持智檢測試看到的效果)

    • 資料匯入之後自動建立測試任務,操作人員登入平臺人工開啟任務
    • 任務名稱:工具接入_2020-07-04_12:22:30
  6. 支援匯入進度檢視

    • 匯入總量及百分比
    • 匯入成功數量及錯誤數量
  7. 支援檢視工具執行日誌

  8. 工具為windows exe格式


頁面設計原型


實際效果


swing 工具包的元件使用

JFrame

public class MainFrame extends JFrame {
    public MainFrame(String title, int width,  int height) {
        this.setLayout(null);
        this.setSize(width, height);//尺寸大小, 單位畫素
        this.setTitle(title);//標題
        //修改logo
        Image icon = Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("favicon.ico"));
        this.setIconImage(icon);
        //String imagePath = "static/favicon.ico";
        //ImageIcon icon = new ImageIcon(imagePath);
        //this.setIconImage(icon.getImage());
        this.getContentPane().setBackground(Color.WHITE);//背景色
        this.setLocationRelativeTo(null);//取消相對定位
        this.setResizable(true);//尺寸是否可變
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//預設關閉操作
    }
}

JButton

public class AITrafficListener extends JButton {
    //單例
    private AITrafficListener(String text, Color color){
        this.setText(text);
        this.setBounds(ScreenSize.getWidth() / 4 - BaseConstant.CONST210, BaseConstant.CONST0, BaseConstant.CONST200, BaseConstant.CONST50);
        this.setFont(FontClass.boldFont20);
        this.setForeground(Color.WHITE);
        this.setBorderPainted(false);//去掉邊框
        this.setFocusPainted(false);//去掉按鈕文字周圍的焦點框
        this.setBackground(color);
        //事件繫結
        this.addActionListener();
    }
    public static AITrafficListener instance;//準備一個類屬性,指向一個例項化物件。 因為是類屬性,所以只有一個
    //public static 方法,返回例項物件
    public static AITrafficListener getInstance(String text, Color color){
        if(null==instance){//第一次訪問的時候,發現instance沒有指向任何物件,這時例項化一個物件
            instance = new AITrafficListener(text, color);
        }
        return instance;//返回 instance指向的物件
    }

    //事件繫結
    public void addActionListener() {
        //按鈕點選事件繫結
        this.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (StartButton.instance.isEnabled()) {//開始接入按鈕開啟時允許切換
                    AITrafficConfigPanel.instance.setVisible(true);
                    AIQualityConfigPanel.instance.setVisible(false);
                    AITrafficConfigPanel.instance.addComponents();//新增元件
                    //切換顏色/字型
                    AITrafficListener.instance.setBackground(ColorClass.color_18a5d6);
                    AIQualityListener.instance.setBackground(ColorClass.color_bbbbbb);
                    AITrafficListener.instance.setFont(FontClass.boldFont20);
                    AIQualityListener.instance.setFont(FontClass.font20);
                    BootStrap.business= BusinessConstant.AI_TRAFFIC_USINESS_MODE;//切換業務模式
                    //合成圖模式隱藏
                    CombinedPicRule.instance.combinedPicTypeText.setVisible(AIQualityConfigPanel.instance.isVisible() && ImageDataMode.instance.compositeModeText.isSelected());
                    CombinedPicRule.instance.carNumPicIndexLabel.setVisible(AIQualityConfigPanel.instance.isVisible() && ImageDataMode.instance.compositeModeText.isSelected());
                    CombinedPicRule.instance.carNumPicIndex.setVisible(AIQualityConfigPanel.instance.isVisible() && ImageDataMode.instance.compositeModeText.isSelected());
                    CombinedPicRule.instance.recogPicIndexLabel.setVisible(AIQualityConfigPanel.instance.isVisible() && ImageDataMode.instance.compositeModeText.isSelected());
                    CombinedPicRule.instance.recogPicIndex.setVisible(AIQualityConfigPanel.instance.isVisible() && ImageDataMode.instance.compositeModeText.isSelected());
                    //替換url
                    String url = AccessURL.instance.getUrl();
                    url = url.replace(BusinessConstant.AIQUALITY_ACCESS_URL, BusinessConstant.AITRAFFIC_ACCESS_URL);//替換URL中間部分
                    AccessURL.instance.accessUrlText.setText(url);
                }
            }
        });

        //按鈕懸停事件繫結MouseAdapter
        this.addMouseListener(new MouseAdapter() {
            public void mouseEntered(MouseEvent e) {
                AITrafficListener.instance.setFont(FontClass.boldFont20);
            }

            public void mouseExited(MouseEvent e) {
                if (!AITrafficConfigPanel.instance.isVisible()) {
                    AITrafficListener.instance.setFont(FontClass.font20);
                }
            }
        });
    }
}

JPanel

public class ConfigPanel extends JPanel {
    //單例面板類
    private ConfigPanel(Color color){
        this.setLayout(null);
        this.setBackground(color);
        this.setBorder(null);//去掉邊框
        this.addComponents();
    }//私有化構造方法使得該類無法在外部通過new 進行例項化
    public static ConfigPanel instance;//準備一個類屬性,指向一個例項化物件。 因為是類屬性,所以只有一個
    //public static 方法,提供給呼叫者,建立一次
    public static ConfigPanel createInstance(Color color){
        if(null==instance){//第一次訪問的時候,發現instance沒有指向任何物件,這時例項化一個物件
            instance = new ConfigPanel(color);
        }
        return instance;
    }

    /**
     * 新增選單元件
     */
    public void addComponents(){
        //導航選單
    }
}

JScrollPane(滾動條)

public class LogScrollPanel extends JScrollPane {
    //單例面板類
    private LogScrollPanel(){
        this.setBackground(Color.WHITE);//背景色
        this.setForeground(Color.ORANGE);//設定字型顏色
        this.setBorder(BorderFactory.createTitledBorder(null, " 日誌區 ", TitledBorder.LEFT, TitledBorder.ABOVE_TOP, FontClass.boldFont16, ColorClass.color_18a5d6));
        this.setBounds(ScreenSize.getWidth() / 2, BaseConstant.CONST0, ScreenSize.getWidth() / 2, ScreenSize.getHeight() - BaseConstant.CONST45);
        this.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);//水平滾動條
        this.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);//垂直滾動條
        //新增第二層 JPane
        this.setViewportView(LogPanel.instance);
    }//私有化構造方法使得該類無法在外部通過new 進行例項化
    public static LogScrollPanel instance = new LogScrollPanel();//準備一個類屬性,指向一個例項化物件。 因為是類屬性,所以只有一個
}

JSplitPane

//分割配置面板 與 日誌面板
public class SplitPanel extends JSplitPane {
    //單例面板類
    private SplitPanel(){
        this.setBorder(null);
        this.setOrientation(JSplitPane.HORIZONTAL_SPLIT);//設定分割線方向 縱向分佈
        this.setDividerSize(6);//設定分割線的寬度
        this.setDividerLocation(ScreenSize.getWidth()/2);//設定分割線位於中央
        this.setOneTouchExpandable(false);//設定那個槓槓上的兩個黑點顯示
        //this.setEnabled(true);//設定分割能不能移動,拖動左右面板
        this.setBackground(Color.WHITE);
    }//私有化構造方法使得該類無法在外部通過new 進行例項化
    public static SplitPanel instance;//準備一個類屬性,指向一個例項化物件。 因為是類屬性,所以只有一個
    //public static 方法,提供給呼叫者,建立一次
    public static SplitPanel createInstance(){
        if(null==instance){//第一次訪問的時候,發現instance沒有指向任何物件,這時例項化一個物件
            instance = new SplitPanel();
        }
        return instance;
    }
}

設定windows介面, 下拉框, 複選框樣式

public static void setWindowStyle(){
    try {
        //介面風格
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());//設定為當前系統風格
        //UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");//Windows風格
        //UIManager.setLookAndFeel("com.sun.java.swing.plaf.motif.MotifLookAndFeel") ; //Mac風格
        //UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel") ;//Java預設風格
        //下拉框, 複選框樣式
        SwingUtilities.updateComponentTreeUI(Separator.instance.separatorText);//分隔符
        SwingUtilities.updateComponentTreeUI(TimeFormat.instance.timeFormatText);//時間格式
        SwingUtilities.updateComponentTreeUI(ProcessNum.instance.processNumText);//程序數量
        SwingUtilities.updateComponentTreeUI(ImageDataMode.instance.compositeModeText);//合成圖
        SwingUtilities.updateComponentTreeUI(CombinedPicRule.instance.combinedPicTypeText);//合成圖型別
        SwingUtilities.updateComponentTreeUI(ImageDataMode.instance.sequenceModeText);//序列圖
        SwingUtilities.updateComponentTreeUI(RecordId.instance.checkBoxValue);//RecordId
        SwingUtilities.updateComponentTreeUI(IllegalTime.instance.checkBoxValue);//違法時間
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

設定UI預設字型

public static void setUIFont (javax.swing.plaf.FontUIResource font){
    Enumeration keys = UIManager.getDefaults().keys();
    while (keys.hasMoreElements()) {
        Object key = keys.nextElement();
        Object value = UIManager.get(key);
        if (value instanceof javax.swing.plaf.FontUIResource)
            UIManager.put (key, font);
    }
}

滑鼠點選事件

//按鈕點選事件繫結
this.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        if (StartButton.instance.isEnabled()) {//程式啟動後不允許切換配置頁
            AIQualityConfigPanel.instance.setVisible(true);
            AITrafficConfigPanel.instance.setVisible(false);
            AIQualityConfigPanel.instance.addComponents();//新增元件
            //切換顏色/字型
            AIQualityListener.instance.setBackground(ColorClass.color_18a5d6);
            AITrafficListener.instance.setBackground(ColorClass.color_bbbbbb);
            AIQualityListener.instance.setFont(FontClass.boldFont20);
            AITrafficListener.instance.setFont(FontClass.font20);
            //切換業務模式
            BootStrap.business = BusinessConstant.AI_QUALITY_USINESS_MODE;
            //合成圖模式顯示
            CombinedPicRule.instance.combinedPicTypeText.setVisible(AIQualityConfigPanel.instance.isVisible() && ImageDataMode.instance.compositeModeText.isSelected());
            CombinedPicRule.instance.carNumPicIndexLabel.setVisible(AIQualityConfigPanel.instance.isVisible() && ImageDataMode.instance.compositeModeText.isSelected());
            CombinedPicRule.instance.carNumPicIndex.setVisible(AIQualityConfigPanel.instance.isVisible() && ImageDataMode.instance.compositeModeText.isSelected());
            CombinedPicRule.instance.recogPicIndexLabel.setVisible(AIQualityConfigPanel.instance.isVisible() && ImageDataMode.instance.compositeModeText.isSelected());
            CombinedPicRule.instance.recogPicIndex.setVisible(AIQualityConfigPanel.instance.isVisible() && ImageDataMode.instance.compositeModeText.isSelected());
            //更換推送地址URL
            String url = AccessURL.instance.getUrl();
            url = url.replace(BusinessConstant.AITRAFFIC_ACCESS_URL, BusinessConstant.AIQUALITY_ACCESS_URL);//替換URL中間部分
            AccessURL.instance.accessUrlText.setText(url);
        }
    }
});

滑鼠懸停離開事件

//按鈕懸停事件繫結MouseAdapter
this.addMouseListener(new MouseAdapter() {
    public void mouseEntered(MouseEvent e) {
        AIQualityListener.instance.setFont(FontClass.boldFont20);
    }

    public void mouseExited(MouseEvent e) {
        if (!AIQualityConfigPanel.instance.isVisible()) {
            AIQualityListener.instance.setFont(FontClass.font20);
        }
    }
});

需要注意的地方

maven 打包成 jar, 執行 jar 程式包, logo 不能正常顯示, 是maven 打包時沒有把圖片打包在內; 可以把圖片放在編譯後的目錄, 然後在程式中通過 getResource() 去獲取, 就可以了.

//修改logo
Image icon = Toolkit.getDefaultToolkit().getImage(this.getClass().getResource("favicon.ico"));
this.setIconImage(icon);


滾動條

需要巢狀才能實現, 巢狀關係是:

JScrollPane (第一層) --> JPanel (第二層) --> JTextPane(第三層)

JScrollPane 第一層


public class LogScrollPanel extends JScrollPane {
    //單例面板類
    private LogScrollPanel(){
        this.setBackground(Color.WHITE);//背景色
        this.setForeground(Color.ORANGE);//設定字型顏色
        this.setBorder(BorderFactory.createTitledBorder(null, " 日誌區 ", TitledBorder.LEFT, TitledBorder.ABOVE_TOP, FontClass.boldFont16, ColorClass.color_18a5d6));
        this.setBounds(ScreenSize.getWidth() / 2, BaseConstant.CONST0, ScreenSize.getWidth() / 2, ScreenSize.getHeight() - BaseConstant.CONST45);
        this.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);//水平滾動條
        this.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);//垂直滾動條
        //新增第二層 JPane
        this.setViewportView(LogPanel.instance);
    }//私有化構造方法使得該類無法在外部通過new 進行例項化
    public static LogScrollPanel instance = new LogScrollPanel();//準備一個類屬性,指向一個例項化物件。 因為是類屬性,所以只有一個
}

JPanel 第二層

//JPanel (第二層)
public class LogPanel extends JPanel {
    //單例面板類
    private LogPanel(){
        this.setLayout(new FlowLayout(FlowLayout.LEFT, 1, 1));//設定為其內容實際的高度
        this.setBackground(Color.BLACK);
        //this.setBounds(ScreenSize.getWidth() / 2, BaseConstant.CONST0, ScreenSize.getWidth() / 2, ScreenSize.getHeight() - BaseConstant.CONST45);
        //新增第三層 JTextPanel
        this.add(LogTextPane.instance);
    }//私有化構造方法使得該類無法在外部通過new 進行例項化
    public static LogPanel instance = new LogPanel();//準備一個類屬性,指向一個例項化物件。 因為是類屬性,所以只有一個
}

JTextPane 第三層 + 新增內容方法(日誌記錄)

public class LogTextPane extends JTextPane {
    //單例面板類
    private LogTextPane(){
        this.setLayout(null);
        this.setBackground(Color.BLACK);
        this.setFont(FontClass.font14);
        //this.setBounds(BaseConstant.CONST0, BaseConstant.CONST0, ScreenSize.getWidth() / 2, ScreenSize.getHeight());
        this.setEditable(false);//不可編輯
    }//私有化構造方法使得該類無法在外部通過new 進行例項化
    public static LogTextPane instance = new LogTextPane();//準備一個類屬性,指向一個例項化物件。 因為是類屬性,所以只有一個

    public void debug(String logInfo) {
        Style style = this.getStyledDocument().addStyle(null, null);// 獲取元件空樣式,addStyle(null, null)會返回一個空樣式
        StyleConstants.setForeground(style, Color.GREEN);// 將style的設定顏色
        this.append(logInfo, style);//追加日誌
    }

    public void info(String logInfo) {
        Style style = this.getStyledDocument().addStyle(null, null);// 獲取元件空樣式,addStyle(null, null)會返回一個空樣式
        StyleConstants.setForeground(style, Color.WHITE);// 將style的設定顏色
        this.append(logInfo, style);//追加日誌
    }

    public void warning(String logInfo) {
        Style style = this.getStyledDocument().addStyle(null, null);// 獲取元件空樣式,addStyle(null, null)會返回一個空樣式
        StyleConstants.setForeground(style, Color.ORANGE);// 將style的設定顏色
        this.append(logInfo, style);//追加日誌
    }

    public void error(String logInfo) {
        Style style = this.getStyledDocument().addStyle(null, null);// 獲取元件空樣式,addStyle(null, null)會返回一個空樣式
        StyleConstants.setForeground(style, Color.RED);// 將style的設定顏色
        this.append(logInfo, style);//追加日誌
    }
    
    public void append(String logInfo, Style style){
        if (logInfo != null) {
            int contentLenth = this.getStyledDocument().getLength();// 這一句是獲取當前面板內容的總長度,
            try {
                // 作為要插入內容的偏移量 this._new.getText()+"\n"這一句是獲取輸入面板內容 style這一句是使用的樣式
                this.getStyledDocument().insertString(contentLenth, logInfo + "\n", style);
            } catch (BadLocationException e) {
                e.printStackTrace();
            }
            //實現垂直滾動條自動下滑到最低端
            this.setCaretPosition(this.getStyledDocument().getLength());
        }
    }
}

最後給出web專案地址: https://github.com/kaichenkai/DataAccessTools




完 !