[英]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.