【问题标题】:JavaFx Change Window, Without New Controller ConstructorJavaFx 更改窗口,没有新的控制器构造函数
【发布时间】:2017-08-13 16:58:51
【问题描述】:

我有 2 个 fxml 文件。示例 A.fxml。 B.fxml。我有 2 个控制器。 AController (A.fxml) BController (B.fxml)。 A fxml 和 B fxml 有更改按钮更改场景或 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 更改按钮中的代码相同。当我单击更改按钮扫描更改。但每次 init 方法和控制器构造器也在工作。当用户每次使用新的构造函数更改 fxml javafx 时。如何在没有新控制器构造函数的情况下更改窗口?

【问题讨论】:

    标签: java javafx


    【解决方案1】:

    使用视图模型:

    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);
        }
    }
    

    【讨论】:

    • 你有这样的示例项目吗?或者你可以写简单的maven项目吗? A fxml 和 B fxml AController BController。我期望太多,我知道。但如果你这样做,我将不胜感激。
    • @VolkanOkçu 已更新完整示例。
    • 非常感谢。我对此表示感谢。
    猜你喜欢
    • 2018-06-04
    • 1970-01-01
    • 2016-10-20
    • 1970-01-01
    • 2020-09-05
    • 1970-01-01
    • 2014-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多