【问题标题】:How to swap screens in a JavaFX application in the controller class?如何在控制器类的 JavaFX 应用程序中交换屏幕?
【发布时间】:2012-09-30 01:23:14
【问题描述】:

如果JavaFX项目中有3个文件; FXML 文件、FXML 控制器和应用程序类;控制器如何通过更改单击时的屏幕(通常使用stage.setScreen() 完成)来响应按钮单击(效果很好)?我没有提到舞台(传递给应用程序类的start(Stage))。

应用示例:

public class JavaFXApplication4 extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("Sample.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

    /**
     * The main() method is ignored in correctly deployed JavaFX application.
     * main() serves only as fallback in case the application can not be
     * launched through deployment artifacts, e.g., in IDEs with limited FX
     * support. NetBeans ignores main().
     *
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}

FXML 示例:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200.0" prefWidth="320.0"  xmlns:fx="http://javafx.com/fxml" fx:controller="javafxapplication4.SampleController">
  <children>
  <Button id="button" fx:id="nextScreen" layoutX="126.0" layoutY="90.0" onAction="#handleButtonAction" text="Next Screen" />
  <Label fx:id="label" layoutX="126.0" layoutY="120.0" minHeight="16.0" minWidth="69.0" />
  </children>
</AnchorPane>

控制器示例:

public class SampleController implements Initializable {

    @FXML
    private Label label;

    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");

        // Here I want to swap the screen!
    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // ...
    }    
}

【问题讨论】:

    标签: javafx-2 javafx


    【解决方案1】:
    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");
        //Here I want to swap the screen!
    
        Stage stageTheEventSourceNodeBelongs = (Stage) ((Node)event.getSource()).getScene().getWindow();
        // OR
        Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow();
        // these two of them return the same stage
        // Swap screen
        stage.setScene(new Scene(new Pane()));
    }
    

    【讨论】:

    • 非常感谢,这正是我想要的 :)
    • 这很有帮助!谢谢:)
    • 当你在最后输入 "stage.setScene(...)" 时,''stage" 必须是 "stageTheEventSourceNodeBelongs" 或 "stageTheLabelBelongs" 这两个之一吧?
    【解决方案2】:

    我在进入 Java 并试图解决同样的问题时发现了这个老问题。 因为我希望场景记住切换之间的内容,所以我不能使用接受的答案,因为在场景之间切换时它会再次实例化它们(失去它们之前的状态)。

    无论如何,接受的答案和answer to the similar question 给了我一个关于如何在不丢失状态的情况下切换场景的提示。 主要思想是将场景的实例注入另一个控制器,这样控制器就不需要一遍又一遍地实例化一个新的场景,而是可以使用已经存在的实例(及其状态)。

    所以这里是实例化场景的主类:

    public class Main extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage primaryStage) throws Exception {
            // getting loader and a pane for the first scene. 
            // loader will then give a possibility to get related controller
            FXMLLoader firstPaneLoader = new FXMLLoader(getClass().getResource("firstLayout.fxml"));
            Parent firstPane = firstPaneLoader.load();
            Scene firstScene = new Scene(firstPane, 300, 275);
    
            // getting loader and a pane for the second scene
            FXMLLoader secondPageLoader = new FXMLLoader(getClass().getResource("secondLayout.fxml"));
            Parent secondPane = secondPageLoader.load();
            Scene secondScene = new Scene(secondPane, 300, 275);
    
            // injecting second scene into the controller of the first scene
            FirstController firstPaneController = (FirstController) firstPaneLoader.getController();
            firstPaneController.setSecondScene(secondScene);
    
            // injecting first scene into the controller of the second scene
            SecondController secondPaneController = (SecondController) secondPageLoader.getController();
            secondPaneController.setFirstScene(firstScene);
    
            primaryStage.setTitle("Switching scenes");
            primaryStage.setScene(firstScene);
            primaryStage.show();
        }
    }
    

    这是两个控制器:

    public class FirstController {
    
        private Scene secondScene;
    
        public void setSecondScene(Scene scene) {
            secondScene = scene;
        }
    
        public void openSecondScene(ActionEvent actionEvent) {
            Stage primaryStage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
            primaryStage.setScene(secondScene);
        }
    }
    

    是的,第二个看起来一样(可能会共享一些逻辑,但当前状态足以作为概念证明)

    public class SecondController {
    
        private Scene firstScene;
    
        public void setFirstScene(Scene scene) {
            firstScene = scene;
        }
    
        public void openFirstScene(ActionEvent actionEvent) {    
            Stage primaryStage = (Stage)((Node)actionEvent.getSource()).getScene().getWindow();
            primaryStage.setScene(firstScene);
        }
    }
    

    【讨论】:

    • 天哪,这救了我的命!我一直在网上搜索类似的东西,因为所有其他示例每次都从文件中加载资源,但我需要保留场景对象,所以谢谢!
    • 正是我需要的!一旦解释清楚,似乎就很明显了。谢谢!
    【解决方案3】:

    你也可以这样试试。

    public void onBtnClick(ActionEvent event) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("login.fxml"));
            Stage stage = (Stage) btn.getScene().getWindow();
            Scene scene = new Scene(loader.load());
            stage.setScene(scene);
        }catch (IOException io){
            io.printStackTrace();
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2018-07-24
      • 1970-01-01
      • 2016-01-23
      • 1970-01-01
      • 1970-01-01
      • 2020-12-05
      • 1970-01-01
      • 2019-01-26
      相关资源
      最近更新 更多