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


看到JavaFX應用很多人都會說JavaFX應用太丑了,確實JavaFX比起Qt、MFC、Delphi這些界面確實丑了一點,但也不是沒有可以美化的空間。
跟網頁一樣,單純HTML不加任何CSS的時候也不是很美觀,JavaFX如稍微美化一下還是可以接受的。

比如,沒有任何css修飾前的JavaFX應用是這樣的:

經過簡單的修飾之后的JavaFX應用是這樣的:

對比一下,很明顯簡單修飾美化過的界面要比原始的好看很多(個人覺得)。

如果需要將界面改造成上圖的樣式,那么就不能使用JavaFX自帶stage的樣式,需要自己改造一下。
本文涉及的JavaFX用法可以參考之前的文章。

~ JavaFX桌面應用開發系列文章傳送門 ~

  1. JavaFX桌面應用開發-HelloWorld
  2. JavaFX布局神器-SceneBuilder
  3. JavaFX讓UI更美觀-CSS樣式
  4. JavaFX桌面應用-為什么應用老是“未響應”
  5. JavaFX桌面應用-MVC模式開發,“真香”
  6. JavaFX桌面應用-loading界面
  7. JavaFX桌面應用-表格用法
  8. JavaFX桌面應用-視頻轉碼工具
  9. JavaFX桌面應用-SpringBoot + JavaFX

構建自己的JavaFX程序框架,需要解決以下問題:

  1. 取消默認的Stage樣式
  2. 構造自己“最小化”,“關閉”面板
  3. 讓程序可以拖動
  4. 處理“最小化”,“關閉”事件
  5. 構造自己的桌面程序

取消Stage樣式

取消Stage的樣式比較簡單,這個在“JavaFX桌面應用-loading界面”那篇文件已經提過,就是設置Stage的Style為TRANSPARENT即可。

stage.initStyle(StageStyle.TRANSPARENT);

Style為TRANSPARENT之后,應用就沒有了“最小化”、“最大化”、“關閉”面板了,如圖:

這個時候,可以用BorderPane來重構桌面框架,將原來放在Scene的root組件放在BorderPane的CENTER位置,然后自己構造的“最小化”、“最大化”、“關閉”面板放在BorderPane中的TOP位置即可。

構造自己“最小化”、“最大化”、“關閉”面板

按照上面設想的布局,構造自己“最小化”、“最大化”、“關閉”面板,這里我不需要“最大化”按鈕,只需要“最小化”和關閉。
整體的布局為:

HBox[LOGO,標題,最小化,關閉]

這里采用一個HBox里面放置四個Label來實現“最小化”、“關閉”面板,可以在“標題”和“最小化”中間插入一個Pane,采用HGrow將兩邊“撐開”。

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來處理:

.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:

// 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組裝起來即可。

stage.initStyle(StageStyle.TRANSPARENT);
BorderPane borderPane = new BorderPane();
borderPane.setTop(hbox);
borderPane.setCenter(root);
Scene scene = new Scene(borderPane);
stage.setScene(scene);

這樣整個界面框架就構造完成了。

讓程序可以拖動

界面已經構造完成了,但是會發現重構的界面無法拖動,需要自己來實現拖動功能。
界面拖動功能可以通過鼠標的拖拽事件和位置計算來實現,通過鼠標拖拽時的坐標同步更新Stage的坐標來達到拖動效果。

鼠標拖拽事件需要實現EventHandler<MouseEvent>接口:

public class JFXStage implements EventHandler<MouseEvent> {
    private double xOffset = 0;
    private double yOffset = 0;

    @Override
    public void handle(MouseEvent event) {
          if (event.getEventType() == MouseEvent.MOUSE_PRESSED) {
                xOffset = event.getSceneX();
                yOffset = event.getSceneY();
          } else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED) {
                stage.setX(event.getScreenX() - xOffset);
                if (event.getScreenY() - yOffset < 0) {
                      stage.setY(0);
                } else {
                      stage.setY(event.getScreenY() - yOffset);
                }
          }
    }
}

然后讓需要拖拽的組件注冊這個監聽器即可,這里只需要頭部自定義面板那塊可以按住拖動即可,所以只需要HBox注冊這個監聽器即可:

hbox.setOnMousePressed(this);
hbox.setOnMouseDragged(this);

這樣,自己構建的JavaFX桌面框架就可以拖動了,效果如下:

處理“最小化”、“最大化”、“關閉”事件

最后需要做的就是處理,自定義按鈕的那些事件,這個自己構建的JavaFX桌面應用才能實現最小化和關閉功能。

最小化功能通過setIconified來實現,當用戶點擊min這個Label的實現,調用stage的setIconified,將程序最小化:

min.setOnMouseClicked(e -> stage.setIconified(true));

關閉按鈕則復雜一點,要看有沒有注冊關閉回調,如果有就交給回調去處理,如果沒有就直接關閉。

close.setOnMouseClicked(e -> {
    EventHandler<WindowEvent> opt = stage.onCloseRequestProperty().get();
    if (opt != null) {
        opt.handle(new WindowEvent(stage, WindowEvent.WINDOW_CLOSE_REQUEST));
    } else {
        stage.close();
    }
});    

構建自己的桌面程序

使用方面其他流程不變,只是不需要在構建Scene了,然后將Stage和root叫JFXStage去構建即可:

@SpringBootApplication
public class Main extends JFXApplication {
	public static void main(String[] args) {
		launch(Main.class, HelloworldView.class, new CustomStarterScreen(), args);
	}

	@Override
	protected void beforeStageDisplay(Stage stage, Parent root, ConfigurableApplicationContext ctx) {
		JFXStage.of(stage, root).setTitle(" JavaFX桌面應用", null).build();
	}
}

結合Springboot,再構建自己的JavaFX桌面框架不僅界面美化了,而且開發方便了很多。

本文的完成源碼僅JFXStage這個類,可以在公眾號上獲取。

關注公眾號,下次將介紹JavaFX桌面應用如何實現在線升級。

=========================================================
關注 公眾號 “HiIT青年” 發送 “javafx-jfxstage” 獲取源碼。(如果沒有收到回復,可能是你之前取消過關注。)

HiIT青年
關注公眾號,閱讀更多文章。


免責聲明!

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



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