簡體   English   中英

控制器和FXML文件在不同階段之間的連接

[英]Connection between controllers and FXML files on different stages

這幾天我在學習JavaFX,但在這里遇到了這個錯誤:

我正在創建一個簡單的游戲,例如《部落戰爭》 /《部落沖突》。 我的問題是關於如何將信息從一個階段(窗口/confirmSerra.fxml/Controller2.java)發送到已經創建並正在運行的另一個階段(primarystage / aldeiaPage.fxml / aldeiaControl.java)的信息。

我已經知道如何將信息從一個階段發送到另一階段(如果尚未創建)。

這是我的Main.java,它啟動了游戲的principalStage

public class Main extends Application {


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

        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(getClass().getResource("aldeiaPage.fxml"));
        Parent root = fxmlLoader.load();

        primaryStage.setTitle("Jogo_Alpha - Aldeia");
        primaryStage.setScene(new Scene(root, 1024, 768));
        primaryStage.show();
    }

    public static void main(String[] args) {

        launch(args);
    }
}

這是“ aldeiaPage.fxml”中控制器“ aldeiaControl.java”的一部分:

@FXML public void teste1() throws Exception {

    Stage window = new Stage();
    FXMLLoader fxmlLoader = new FXMLLoader();
    fxmlLoader.setLocation(getClass().getResource("confirmSerra.fxml"));

    Pane layout = fxmlLoader.load();
    Scene scene = new Scene(layout);

    Controller2 c =  fxmlLoader.getController();
    window.setTitle("Upgrade Serralheria");

    window.setScene(scene);
    window.show();

    c.labelserraLev.setText(String.valueOf(seralevelNum));
    //seralevelNum is a variable from this controller "aldeiaControl"
}

如您所見,我可以通過單擊teste1按鈕創建一個新階段,該階段鏈接到@FXML文件。 並使其成為FXMLLoader.getController()使我可以訪問另一個控制器中的labelserraLev

Controller2.java

public class Controller2 {


    @FXML public Label labelserraLev;


    @FXML public void buttonclick() throws Exception {

        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.load(getClass().getResource("aldeiaPage.fxml"));

        aldeiaControl labelchange =  fxmlLoader.getController();

        labelchange.seralevel.setText("10");

    }

}

當我單擊此buttonclick() (即下圖中的“升級”按鈕)時,如何更改principalstage的標簽文本(已創建並且仍在運行)? 我可以更改新窗口的標簽文本,但是因為它是一個新窗口,但是關於已經創建的窗口,所以不能。

錯誤是這樣的:

Caused by: java.lang.NullPointerException
at sample.Controller2.buttonclick(Controller2.java:30)

在此處輸入圖片說明

通常,將UI組件暴露在控制器類之外是一種不好的做法:基本上破壞了封裝。 我實際上會更進一步地建議,在大多數情況下,您的控制器甚至都不需要相互引用。

FXML是一個“視圖”,並且與控制器類一起構成了一個稱為“模型-視圖-控制器”的(相當寬松定義的)設計模式的兩個部分。 您在這里缺少的部分是模型。 在某些變體中,控制器由演示者代替,並且可以說,附加到FXML文件的“控制器”的工作方式更像是演示者。

基本思想是模型存儲數據:視圖將數據呈現給用戶,控制器處理用戶輸入並作為響應更新模型。 在模式的某些版本中,控制器/演示者觀察模型中的數據並在視圖更改時更新視圖。 (在其他情況下,視圖會觀察模型並在數據更改時進行更新。)

這種設計的優點是您可以擁有同一數據的多個視圖,這些視圖可以保持同步,而無需彼此了解。 所有視圖/演示者對都觀察模型中的數據,因此,如果一個演示者更新模型,則所有觀察都將通過觀察模型進行更新。

因此,您需要一個保存數據的模型類:

public class Model {

    private final IntegerProperty level = new SimpleIntegerProperty();

    public IntegerProperty levelProperty() {
        return level ;
    }

    public final int getLevel() {
        return levelProperty().get();
    }

    public final void setLevel(int level) {
        levelProperty().set(level);
    }

    // other properties etc...
}

現在,您的控制器需要對模型的引用,並將其視圖綁定到模型:

public class AldeiaControl {

    private Model model ;

    @FXML
    private Label seraLevel ;

    public void setModel(Model model) {
        this.model = model ;
        seraLevel.textProperty().bind(model.levelProperty().asString());
    }

    @FXML public void teste1() throws Exception {

        Stage window = new Stage();
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(getClass().getResource("confirmSerra.fxml"));

        Pane layout = fxmlLoader.load();
        Scene scene = new Scene(layout);

        Controller2 c =  fxmlLoader.getController();
        window.setTitle("Upgrade Serralheria");

        window.setScene(scene);
        window.show();

        c.setModel(model);
    }   

}

public class Controller2 {


    @FXML private Label labelserraLev;

    private Model model ;

    public void setModel(Model model) {
        this.model = model ;
        labelserraLev.textProperty().bind(model.levelProperty().asString());
    }

    @FXML public void buttonclick() throws Exception {

        // will automatically update all properties bound to the model's level:
        model.setLevel(10);

    }

}

最后,創建一個模型並將其提供給控制器:

public class Main extends Application {


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

        Model model = new Model();

        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setLocation(getClass().getResource("aldeiaPage.fxml"));
        Parent root = fxmlLoader.load();

        AldeiaControl controller = fxmlLoader.getController();
        controller.setModel(model);

        primaryStage.setTitle("Jogo_Alpha - Aldeia");
        primaryStage.setScene(new Scene(root, 1024, 768));
        primaryStage.show();
    }

    public static void main(String[] args) {

        launch(args);
    }
}

另請參閱將MVC與JavaFx一起應用

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM