2 回答

TA貢獻1921條經驗 獲得超9個贊
您目前擁有的有幾個問題:
在您的
LoginScreen
構造函數中,您setWindow
使用尚未注入的字段的值進行調用:public LoginScreen(){ super(); setWindow(loginWindow); }
當控制器的構造函數正在執行時,不會注入任何 FXML 字段——意思
loginWindow
是null
. 原因不言而喻:必須FXMLLoader
先構建控制器實例,然后才能開始注入適當的字段。事件的順序是:(1)實例化控制器,(2)注入字段,(3)調用初始化方法;我相信鏈接任何事件處理程序/更改偵聽器都包含在第二步中。這意味著任何需要發生的關于 FXML 字段的初始化都應該在該
initialize
方法中完成。HomeScreen
您在使用 的構造函數中遇到了同樣的問題super(homeWindow)
,盡管還有其他問題將在下一點中解決。除了試圖訪問構造函數中尚未注入的字段外,還有以下兩個問題:
@FXML private static AnchorPane homeWindow = new AnchorPane();
第一個問題是您初始化了一個要注入的字段。永遠不要這樣做。一個好的經驗法則是:如果該字段帶有注釋,
@FXML
則不要手動為其分配值。FXML 字段最終將被注入,這意味著您事先分配給它的任何值都將被簡單地替換。這可能會導致一些細微的問題,因為任何引用先前值的代碼都不會使用實際添加到場景圖中的對象。另一個問題是你的領域是靜態的。JavaFX 8+ 不支持注入靜態字段。據我所知,它在舊版本中曾經是可能的,但這種行為從未得到官方支持(即是一個實現細節)。此外,讓某些固有的基于實例(FXML+控制器)的東西設置一個會影響所有實例的靜態字段是沒有意義的。
一個額外的問題:當你制作
homeWindow
非靜態時,你不能再使用super(homeWindow)
,因為在調用超級構造函數之前你不能引用它。
使用兩個修改后的類應該允許您的代碼運行:
LoginScreen.java:
public class LoginScreen extends ScreenController {
@FXML private AnchorPane loginWindow;
@FXML private Button goButton;
@Override
public void initialize(URL location, ResourceBundle resources) {
super.initialize(location, resources);
setWindow(loginWindow); // set window in initialize method
}
@FXML
public void goButtonPressed(ActionEvent event) throws IOException {
setScreen("Home");
System.out.println("Success.");
}
}
HomeScreen.java:
public class HomeScreen extends ScreenController {
@FXML private AnchorPane homeWindow;
@Override
public void initialize(URL location, ResourceBundle resources) {
super.initialize(location, resources);
setWindow(homeWindow); // set window in initialize method
}
}
但是不要使用:
window.getChildren().setAll(root);
在你的ScreenController#setScreen方法中——它會導致一個微妙的問題。您正在添加 aroot作為節點的子節點window。ScreenController但是,當發生這種情況時, (與新的相關聯)的新實例root將具有其window == root. 換句話說,windowcreated with現在是created withLoginScreen的父級。根據更復雜的應用程序的設計方式,這可能導致“根”的嵌套越來越深。windowHomeScreen
也就是說,您已經有了另一種方法,您可以實際替換整個Scene. 正如您所說,您在那里遇到的問題是調整Stage大小以適應新的Scene. 這可以通過替換 的root而Scene不是Scene本身來解決:
window.getScene().setRoot(root);

TA貢獻1859條經驗 獲得超6個贊
您可以在初始化期間獲得 JavaFX 應用程序的主要階段。其他場景類應該有一個帶有 getter 和 setter 的 Stage 字段,這樣您就可以通過它們的 Controller 傳遞主舞臺。至于窗口調整大小,您可以通過在語句中添加getStage().getWidth()和來解決。getStage().getHeight()setScene()
我要指出的一個小例子:
public class MainClass extends Application {
@Override
public void start(Stage stage) throws Exception {
InputStream sceneStream = MainClass.class.getResourceAsStream("/fxml"+
"/newScene/main.fxml");
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(sceneStream);
Scene scene = new Scene(root);
stage.setTitle("App title");
NewScene controller = loader.getController();
controller.setMainStage(stage);
stage.setScene(scene, stage.getWidth(), stage.getHeight());
stage.show();
}
所以上面的函數從創建主階段的MainClass開始。請注意中間部分與代碼的其余部分有點分離,通過獲取已加載的控制器,Scene我將階段傳遞給它。您可以通過這種方式將舞臺傳遞到所有場景。還要注意設置場景的部分,我在這里使用了兩個從舞臺中提取的參數;寬度和高度。除此之外,還有更多方法可以在主舞臺上運行的幾乎每個場景中獲得舞臺,只需執行以下操作:
@FXML private Button aButton;
public Button getAButton(){
return aButton;
}
Stage stage = (Stage) getAButton().getScene().getWindow();
Node這將適用于基于初級階段的所有場景,并且無論類型如何,只需要在場景圖中注冊即可。
添加回答
舉報