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格式


頁面設計原型

img


實際效果


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());
        }
    }
}

最后給出項目地址: https://github.com/kaichenkai/DataAccessTools
聯系方式: 13018083063(微信同號)




完 !


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM