Java GUI swing 工具包使用總結
前言
最近用 swing 寫了一個GUI圖片接入的工具, 方便用於將圖片資料通過介面推送到 web 專案中
做介面有點像寫原生的 CSS
技術儲備
-
java
基礎知識, 面向物件封裝, 繼承, 介面
匿名內部類, Lambda
-
開發工具
IDEA
功能需求
AI智檢
-
支援合成圖和序列圖
-
工具支援填寫資料地址,根據資料地址自動將資料快速匯入平臺
資料為圖片,圖片資訊在圖片名稱上面,欄位資訊已特定的分隔符連線,各個現場不同
-
工具支援填寫客戶違法編碼
如果填寫了違法編碼,則以填寫為準,否則以欄位對映關係切割為準
-
工具支援填寫合成圖模式
-
工具支援自動根據圖片名稱獲取圖片及相關資訊
-
工具支援自動匹配車牌根據設定規則
如果填寫車牌匹配規則,以匹配為準,否則以欄位對映關係切割為準
-
工具支援預設資料補充
平臺非必須欄位,程式指定預設值
-
平臺支援離線測試資料,快速看到演算法識別指標 (保持智檢測試看到的效果)
-
資料匯入之後自動建立測試任務,操作人員登入平臺人工開啟任務
-
任務名稱:工具接入_2020-07-04_12:22:30
-
-
支援匯入進度檢視
- 匯入總量及百分比
- 匯入成功數量及錯誤數量
-
支援檢視工具執行日誌
-
工具為windows exe格式
AI預審
-
支援合成圖和序列圖
-
工具支援填寫資料地址,根據資料地址自動將資料快速匯入平臺
資料為圖片,圖片資訊在圖片名稱上面,欄位資訊已特定的分隔符連線,各個現場不同
-
工具支援自動根據圖片名稱獲取圖片及相關資訊
-
工具支援預設資料補充
平臺非必須欄位,程式指定預設值
-
平臺支援離線測試資料,快速看到演算法識別指標(保持智檢測試看到的效果)
- 資料匯入之後自動建立測試任務,操作人員登入平臺人工開啟任務
- 任務名稱:工具接入_2020-07-04_12:22:30
-
支援匯入進度檢視
- 匯入總量及百分比
- 匯入成功數量及錯誤數量
-
支援檢視工具執行日誌
-
工具為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);
}
}
});
需要注意的地方
關於 Logo
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