2 回答

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

TA貢獻1859條經(jīng)驗 獲得超6個贊
您可以在初始化期間獲得 JavaFX 應(yīng)用程序的主要階段。其他場景類應(yīng)該有一個帶有 getter 和 setter 的 Stage 字段,這樣您就可以通過它們的 Controller 傳遞主舞臺。至于窗口調(diào)整大小,您可以通過在語句中添加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();
}
所以上面的函數(shù)從創(chuàng)建主階段的MainClass開始。請注意中間部分與代碼的其余部分有點分離,通過獲取已加載的控制器,Scene我將階段傳遞給它。您可以通過這種方式將舞臺傳遞到所有場景。還要注意設(shè)置場景的部分,我在這里使用了兩個從舞臺中提取的參數(shù);寬度和高度。除此之外,還有更多方法可以在主舞臺上運行的幾乎每個場景中獲得舞臺,只需執(zhí)行以下操作:
@FXML private Button aButton;
public Button getAButton(){
return aButton;
}
Stage stage = (Stage) getAButton().getScene().getWindow();
Node這將適用于基于初級階段的所有場景,并且無論類型如何,只需要在場景圖中注冊即可。
添加回答
舉報