我有2个fxml文件。示例A.fxml。 B.fxml。我有2个控制器。 AController(A.fxml)BController(B.fxml)。 fxml和B fxml有更改按钮更改Scene或fxml。这是按钮代码;
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/infoLibrary/view/A.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
Stage stage = (Stage)((Node)event.getSource()).getScene().getWindow();
stage.setScene(scene);
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
BContrroller更改按钮中的相同代码。当我点击更改按钮scane更改。但每次init方法和控制器构造都会起作用。当用户每次使用新构造函数更改fxml javafx时。如何在没有新控制器构造函数的情况下更改窗口?
答案 0 :(得分:0)
使用视图模型:
public class ViewModel {
public enum View {A, B}
private final ObjectProperty<View> currentView = new SimpleObjectProperty<>(View.A);
public ObjectProperty<View> currentViewProperty() {
return currentView ;
}
public final View getCurrentView() {
return currentViewProperty().get();
}
public final View setCurrentView(View view) {
currentViewProperty().set(view);
}
}
现在在AController
执行:
public class AController {
private ViewModel viewModel ;
public void setViewModel(ViewModel viewModel) {
this.viewModel = viewModel ;
}
// button handler:
@FXML
private void goToB(ActionEvent event) {
viewModel.setCurrentView(ViewModel.View.B);
}
}
和BController
类似。
最后,您使用以下内容设置所有内容,该内容仅执行一次(例如,在您的start()
方法中或类似的地方):
Stage stage = ... ; // maybe it's the primary stage in start...
Scene scene = new Scene();
ViewModel viewModel = new ViewModel();
FXMLLoader aLoader = new FXMLLoader(getClass().getResource("/infoLibrary/view/A.fxml"));
Parent a = aLoader.load();
AController aController = aLoader.getController();
aController.setViewModel(viewModel);
FXMLLoader bLoader = new FXMLLoader(getClass().getResource("/infoLibrary/view/B.fxml"));
Parent b = bLoader.load();
BController bController = bLoader.getController();
bController.setViewModel(viewModel);
scene.rootProperty().bind(Bindings.createObjectBinding(() -> {
if (viewModel.getCurrentView() == ViewModel.View.A) {
return a ;
} else if (viewModel.getCurrentView() == ViewModel.View.B) {
return b ;
} else {
return null ;
}
}, viewModel.currentViewProperty());
stage.setScene(scene);
stage.show();
现在两个FXML文件只加载一次(因此控制器只创建一次,而它们的initialize()
方法只调用一次)。通过改变ViewModel
的状态并观察该状态来管理切换,因此当模型状态改变时场景的根被改变。
这是一个完整的SSCCE:
ViewModel.java:
package sceneswitcher;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
public class ViewModel {
public enum View {A, B}
private final ObjectProperty<View> currentView = new SimpleObjectProperty<>(View.A);
public ObjectProperty<View> currentViewProperty() {
return currentView ;
}
public final View getCurrentView() {
return currentViewProperty().get();
}
public final void setCurrentView(View view) {
currentViewProperty().set(view);
}
}
AController.java:
package sceneswitcher;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class AController {
private ViewModel viewModel ;
@FXML
private TextField textField ;
public void setViewModel(ViewModel viewModel) {
this.viewModel = viewModel ;
}
// button handler:
@FXML
private void goToB(ActionEvent event) {
viewModel.setCurrentView(ViewModel.View.B);
}
public String getText() {
return textField.getText();
}
}
A.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.Button?>
<VBox fx:controller="sceneswitcher.AController" spacing="5" alignment="CENTER"
xmlns:fx="http://javafx.com/fxml/1">
<Label text='This is view A'/>
<TextField fx:id="textField" />
<Button onAction="#goToB" text="Go to view B"/>
</VBox>
BController.java:
package sceneswitcher;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
public class BController {
private ViewModel viewModel ;
@FXML
private TextArea textArea ;
public void setViewModel(ViewModel viewModel) {
this.viewModel = viewModel ;
}
// button handler:
@FXML
private void goToA(ActionEvent event) {
viewModel.setCurrentView(ViewModel.View.A);
}
public String getText() {
return textArea.getText();
}
}
B.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.Button?>
<VBox fx:controller="sceneswitcher.BController" spacing="5" alignment="CENTER"
xmlns:fx="http://javafx.com/fxml/1">
<Label text="This is view B"/>
<TextArea fx:id="textArea" />
<Button onAction="#goToA" text="Go to View A"/>
</VBox>
Main.java:
package sceneswitcher;
import java.io.IOException;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws IOException {
ViewModel viewModel = new ViewModel();
FXMLLoader aLoader = new FXMLLoader(getClass().getResource("A.fxml"));
Parent a = aLoader.load();
AController aController = aLoader.getController();
aController.setViewModel(viewModel);
FXMLLoader bLoader = new FXMLLoader(getClass().getResource("B.fxml"));
Parent b = bLoader.load();
BController bController = bLoader.getController();
bController.setViewModel(viewModel);
Scene scene = new Scene(a, 400, 400);
scene.rootProperty().bind(Bindings.createObjectBinding(() -> {
if (viewModel.getCurrentView() == ViewModel.View.A) {
return a ;
} else if (viewModel.getCurrentView() == ViewModel.View.B) {
return b ;
} else {
return null ;
}
}, viewModel.currentViewProperty()));
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}