JavaFX 學習筆記——窗口與控件

前言

現在比較流行的桌面gui框架有WPF、WinForm、Qt、javafx等。其中WPF和WinForm目前還只能在運行Winsows上。Qt(widget)是一個很強大的跨平臺C++框架(不僅是UI),但用C++寫界面實在有點蛋疼,且編譯出來的體積很大。html

JavaFX是基於JAVA的開源桌面框架,筆者曾學習過Qt,打算嘗試使用Java寫桌面應用,如今網上關於JavaFX的教程不時不少,所以在這裏記錄一下學習過程。java

安裝和配置

JavaFX11的環境不包括在JDK中,所以要在配置好JDK11的基礎上單獨配置,具體方法能夠參考JavaFX官網框架

窗口構成

新建工程,在Main.java中輸入下列代碼:ide

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception{

        VBox layout = new VBox();
        Label label = new Label("Hello world");
        layout.getChildren().add(label);

        Scene scene = new Scene(layout, 300, 300);

        primaryStage.setTitle("Hello World");
        primaryStage.setScene(scene);
        primaryStage.show();
    }


    public static void main(String[] args) {
        launch(args);
    }
}

JavaFX中的Stage能夠看做是窗口,Scene是窗口中的內容,調用StagesetScene函數來設置窗口內容,窗口能夠在運行時切換顯示的Scene,實現Tab頁面的效果。函數

VBox是JavaFX中的一種佈局,其中的元素縱向排列,向VBox中添加元素須要調用vbox.getChildren().add(control),如上所示。佈局

構造Scene時傳入頂層的佈局(相似Qt中QMainWindowCentralWidget)及大小。最後調用show函數將窗口顯示出來。學習

按鈕控件

控件(Control)是GUI框架中最重要的部分,也是用戶與程序進行交互的媒介。ui

在JavaFX中使用控件須要導入包,例如.net

import javafx.scene.control.Label;
import javafx.scene.control.*;

框架中不一樣控件的使用方法大同小異,這裏用最經常使用的按鈕做爲示例。code

在窗口中添加按鈕

構造一個Button對象並添加到VBox中:

Button button = new Button("Click me");
VBox layout = new VBox();
layout.getChildren().add(button);

Scene scene = new Scene(layout, 300, 300);
primaryStage.setScene(scene);

處理按鈕點擊事件

使用EventHandler接口

建立Handler類實現EventHandler接口

class Handler implements EventHandler<ActionEvent> {

    @Override
    public void handle(ActionEvent actionEvent) {
        if(actionEvent.getSource() instanceof Button)
            ((Button) actionEvent.getSource()).setText("Click me again");
    }
}

爲按鈕註冊點擊方法

button.setOnAction(new Handler());

Button還有setOnMouseClicked,setOnTouchPressed等方法,這些是專門爲處理鼠標事件及觸摸事件,setOnAction函數用來處理按鈕觸發事件(無論按鈕被哪一種方式觸發,具體參考文檔)。

由代碼能夠得出,setOnAction函數接收一個EventHandler接口,接口的handle方法用來處理事件。

使用匿名內部類

與上一方法同理,咱們可使用匿名內部類建立接口

button.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent actionEvent) {
        if(actionEvent.getSource() instanceof Button)
            ((Button) actionEvent.getSource()).setText("Click me again");
    }
});

使用Lambda表達式

Java中的一些接口能夠由lambda表達式代替,所以能夠在setOnAction中傳入lambda表達式:

button.setOnAction(actionEvent -> {
    if(actionEvent.getSource() instanceof Button){
        ((Button) actionEvent.getSource()).setText("Click me again");
    }
});

這樣就能夠在實現簡單的事件處理器時沒必要再特地實現接口。

其餘控件

使用其餘控件的方法也都相似按鈕,使用時能夠查詢文檔,或者根據IDE的代碼提示獲知函數簽名及使用方法。

多窗口

在一個桌面程序中每每有多個窗口,下面介紹添加窗口的方法。

建立窗口

添加MsgBox

public class MsgBox {
    public static void show(String title) {
        Stage window = new Stage();
        window.setTitle(title);


        Button trueButton = new Button("True");
        Button falseButton = new Button("False");

        HBox hBox = new HBox(10);    //10爲元素間空隙
        hBox.getChildren().addAll(trueButton, falseButton);
        Scene scene = new Scene(hBox, 100, 100);
        window.setScene(scene);
        window.show();
    }
}

與主窗口建立過程相同,新建stageScene、佈局及控件,最後使用Stageshow方法顯示出來。

調用MsgBox類的show方法便可顯示窗口,函數的參數爲窗口的標題。

設置主窗口中的按鈕事件,點擊按鈕後會顯示一個MsgBox窗口。

button.setOnAction(actionEvent -> MsgBox.show("SubWindow"));

窗口模態

Stage對象可使用initModality方法設置窗口模態類型

window.initModality(Modality.WINDOW_MODAL);

類型包括 Modality.NONE, Modality.WINDOW_MODAL, Modality.APPLICATION_MODAL

  • Modality.NONE: 不阻塞任何窗口
  • Modality.WINDOW_MODAL: 窗口級別的模態,僅僅阻塞與對話框關聯的窗口,用戶能夠正常訪問其餘窗口,適合用於多窗口的程序。
  • Modality.APPLICATION_MODAL(默認值): 應用程序級別的模態,窗口將阻塞整個程序,沒法訪問程序中其餘的窗口

返回子窗口的值

有時咱們須要獲得用戶在子窗口中的操做,例如在本文的例子中,獲知用戶點了哪個按鈕。

接下來實現這樣的功能——點擊True按鈕就在控制檯打印true,不然打印'false'。

更改MsgBox中的代碼

public static boolean show(String title) {
    Stage window = new Stage();
    window.setTitle(title);

    Button trueButton = new Button("True");
    Button falseButton = new Button("False");

    trueButton.setOnAction(actionEvent -> {
        answer = true;
        window.close();
    });

    falseButton.setOnAction(actionEvent -> {
        answer = false;
        window.close();
    });

    HBox hBox = new HBox(10);
    hBox.getChildren().addAll(trueButton, falseButton);
    Scene scene = new Scene(hBox, 100, 100);
    window.setScene(scene);
    window.showAndWait();

    return answer;
}

show函數返回一個boolean類型的值,這個值是由點擊的按鈕決定的,按鈕點擊後會關閉窗口,返回布爾值。

設置主窗口中按鈕點擊事件

button.setOnAction(actionEvent ->
{
        var result = MsgBox.show("SubWindow");
        System.out.println(result);
});

showAndWait函數

這個函數會阻塞當前事件,直到窗口被關閉後纔會返回,並執行接下類的語句。在上例中,咱們顯示窗口並等待,直到點擊按鈕使窗口被關閉,才執行後面的return answer語句。

能夠嘗試改成調用show方法,觀察返回的結果。

窗口的關閉

有時在用戶關閉窗口時,須要執行必定的操做,例如保存設置、確認是否退出等。

這時咱們能夠經過setOnCloseRequest函數設置窗口關閉時觸發的事件

window.setOnCloseRequest(windowEvent ->
{
    System.out.println("The window will be closed!");
});

JavaFX在關閉窗口時,首先執行這一事件處理函數,再將窗口關閉。但在某些狀況下(例如確認是否關閉),咱們須要在處理事件時取消窗口的關閉,這種狀況下能夠調用windowEventconsume方法,告訴事件系統,此事件已經被處理完畢,沒必要再執行其餘處理動做(如關閉窗口)。

將主窗口的代碼改成:

@Override
public void start(Stage primaryStage) throws Exception {

    Button button = new Button("Click me");
    button.setOnAction(actionEvent ->
    {
        var result = MsgBox.show("SubWindow");
        System.out.println(result);
    });
    VBox layout = new VBox();
    layout.getChildren().add(button);

    Scene scene = new Scene(layout, 300, 300);
    primaryStage.setScene(scene);

    primaryStage.setTitle("Hello World");
    primaryStage.setOnCloseRequest(windowEvent -> {
        var result = MsgBox.show("Do you want to CLOSE?");
        if (result == false) {
            windowEvent.consume();
        }
    });
    primaryStage.show();
}

當用戶點擊關閉按鈕時,將會彈窗詢問是否關閉,若用戶點擊False按鈕窗口就不會被關閉。

連接

  1. 推薦一個很好的JavaFX教程視頻:https://youtu.be/FLkOX4Eez6o
  2. 一個適合初學者的Qt教程:https://www.devbean.net/2012/...
相關文章
相關標籤/搜索