2 回答

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

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