1. 程式人生 > >JavaFX桌面應用-構建程式框架

JavaFX桌面應用-構建程式框架

看到JavaFX應用很多人都會說JavaFX應用太醜了,確實JavaFX比起Qt、MFC、Delphi這些介面確實醜了一點,但也不是沒有可以美化的空間。 跟網頁一樣,單純HTML不加任何CSS的時候也不是很美觀,JavaFX如稍微美化一下還是可以接受的。 比如,沒有任何css修飾前的JavaFX應用是這樣的: ![](https://img2020.cnblogs.com/blog/2083963/202009/2083963-20200919202638226-1866767746.png) 經過簡單的修飾之後的JavaFX應用是這樣的: ![](https://img2020.cnblogs.com/blog/2083963/202009/2083963-20200919202749767-1510308983.png) 對比一下,很明顯簡單修飾美化過的介面要比原始的好看很多(個人覺得)。 如果需要將介面改造成上圖的樣式,那麼就不能使用JavaFX自帶stage的樣式,需要自己改造一下。 本文涉及的JavaFX用法可以參考之前的文章。 ~ JavaFX桌面應用開發系列文章傳送門 ~ 1. [JavaFX桌面應用開發-HelloWorld](https://www.cnblogs.com/itqn/p/13379866.html) 2. [JavaFX佈局神器-SceneBuilder](https://www.cnblogs.com/itqn/p/13380499.html) 3. [JavaFX讓UI更美觀-CSS樣式 ](https://www.cnblogs.com/itqn/p/13381560.html) 4. [JavaFX桌面應用-為什麼應用老是“未響應”](https://www.cnblogs.com/itqn/p/13388247.html) 5. [JavaFX桌面應用-MVC模式開發,“真香”](https://www.cnblogs.com/itqn/p/13462943.html) 6. [JavaFX桌面應用-loading介面](https://www.cnblogs.com/itqn/p/13543681.html) 7. [JavaFX桌面應用-表格用法](https://www.cnblogs.com/itqn/p/13387577.html) 8. [JavaFX桌面應用-視訊轉碼工具](https://www.cnblogs.com/itqn/p/13505579.html) 9. [JavaFX桌面應用-SpringBoot + JavaFX](https://www.cnblogs.com/itqn/p/13545604.html) 構建自己的JavaFX程式框架,需要解決以下問題: 1. 取消預設的Stage樣式 2. 構造自己“最小化”,“關閉”面板 3. 讓程式可以拖動 4. 處理“最小化”,“關閉”事件 5. 構造自己的桌面程式 ### 取消Stage樣式 取消Stage的樣式比較簡單,這個在“JavaFX桌面應用-loading介面”那篇檔案已經提過,就是設定Stage的Style為TRANSPARENT即可。 ```java stage.initStyle(StageStyle.TRANSPARENT); ``` Style為TRANSPARENT之後,應用就沒有了“最小化”、“最大化”、“關閉”面板了,如圖: ![](https://img2020.cnblogs.com/blog/2083963/202009/2083963-20200919204211085-1078905790.png) 這個時候,可以用`BorderPane`來重構桌面框架,將原來放在Scene的root元件放在BorderPane的CENTER位置,然後自己構造的“最小化”、“最大化”、“關閉”面板放在BorderPane中的TOP位置即可。 ![](https://img2020.cnblogs.com/blog/2083963/202009/2083963-20200919204650616-880502652.png) ### 構造自己“最小化”、“最大化”、“關閉”面板 按照上面設想的佈局,構造自己“最小化”、“最大化”、“關閉”面板,這裡我不需要“最大化”按鈕,只需要“最小化”和關閉。 整體的佈局為: ``` HBox[LOGO,標題,最小化,關閉] ``` 這裡採用一個HBox裡面放置四個Label來實現“最小化”、“關閉”面板,可以在“標題”和“最小化”中間插入一個Pane,採用HGrow將兩邊“撐開”。 ```java HBox hbox = new HBox(); // LOGO Label logo = new Label(); hbox.getChildren().add(logo); // TITLE Label titleLbl = new Label(title); hbox.getChildren().add(titleLbl); // PANE Pane pane = new Pane(); HBox.setHgrow(pane, Priority.ALWAYS); hbox.getChildren().add(pane); // MIN Label min = new Label(); hbox.getChildren().add(min); // CLOSE Label close = new Label(); hbox.getChildren().add(close); ``` 程式碼只用到了兩個容器(HBox、Pane)和一個控制元件(Label),而所有具體的內容交給CSS來處理: ```css .hbox{ -fx-background-color: #40444f; } .logo{ -fx-background-radius: 2px; -fx-background-position: center center; -fx-background-repeat: no-repeat; -fx-background-size: 35px 35px; -fx-background-color: transparent; -fx-background-image: url("/images/logo.jpg"); -fx-border-width: 0; } .title{ -fx-text-fill: #fff; } .close{ -fx-background-position: center center; -fx-background-repeat: no-repeat; -fx-background-size: 43px 34px; -fx-background-color: transparent; -fx-background-image: url("/images/close_0.png"); -fx-cursor: hand; -fx-border-width: 0; } .close:hover{ -fx-background-color: #f45454; -fx-background-image: url("/images/close_1.png"); -fx-border-width: 0; } .min{ -fx-background-position: center center; -fx-background-repeat: no-repeat; -fx-background-size: 43px 34px; -fx-background-color: transparent; -fx-background-image: url("/images/min_0.png"); -fx-cursor: hand; -fx-border-width: 0; } .min:hover{ -fx-background-color: derive(#ddd, 10%); -fx-background-image: url("/images/min_1.png"); -fx-border-width: 0; } ``` 然後讓HBox容器載入這個CSS,併為每個控制元件設定對一個的class: ```java // HBox hbox.getStylesheets().add(this.getClass().getResource("/css/title-hbox.css").toExternalForm()); hbox.getStyleClass().add(hboxCssClass); // LOGO logo.getStyleClass().add(logoCssClass); // TITLE titleLbl.getStyleClass().add(this.titleCssClass); // MIN min.getStyleClass().add(minCssClass); // CLOSE close.getStyleClass().add(closeCssClass); ``` 面板構建完成後,只需要將它跟原來Scene的root用BorderPane組裝起來即可。 ```java stage.initStyle(StageStyle.TRANSPARENT); BorderPane borderPane = new BorderPane(); borderPane.setTop(hbox); borderPane.setCenter(root); Scene scene = new Scene(borderPane); stage.setScene(scene); ``` 這樣整個介面框架就構造完成了。 ### 讓程式可以拖動 介面已經構造完成了,但是會發現重構的介面無法拖動,需要自己來實現拖動功能。 介面拖動功能可以通過滑鼠的拖拽事件和位置計算來實現,通過滑鼠拖拽時的座標同步更新Stage的座標來達到拖動效果。 滑鼠拖拽事件需要實現`EventHandler