Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javafx 在同一场景中加载新的fxml_Javafx_Fxml_Scene - Fatal编程技术网

Javafx 在同一场景中加载新的fxml

Javafx 在同一场景中加载新的fxml,javafx,fxml,scene,Javafx,Fxml,Scene,我有2个fxml文件: 布局(标题、菜单栏和内容) Anchorpane(应该放在另一个fxml文件的内容中) 我想知道如何在“主”场景的内容空间中加载第二个文件。在javaFX中工作是一件好事,还是加载一个新场景更好 我正试图做类似的事情,但不起作用: @FXML private AnchorPane content; @FXML private void handleButtonAction(ActionEvent event) { content = (Anc

我有2个fxml文件:

  • 布局(标题、菜单栏和内容)
  • Anchorpane(应该放在另一个fxml文件的内容中)
我想知道如何在“主”场景的内容空间中加载第二个文件。在javaFX中工作是一件好事,还是加载一个新场景更好

我正试图做类似的事情,但不起作用:

@FXML
private AnchorPane content;

@FXML
private void handleButtonAction(ActionEvent event) {        
    content = (AnchorPane) FXMLLoader.load("vista2.fxml");
}

谢谢您的帮助。

其他人可能有更好的解决方案,但我的解决方案是在外部fxml中使用一个简单的容器,如VBox,然后加载新内容并将其作为容器的子容器添加。如果您只加载一个或两个表单,这可能是一种方法。然而,对于一个更完整的框架,我发现这篇博文很有帮助:她为她的框架提供了源代码,其中包括奇特的转换。虽然它旨在管理顶级场景,但我发现它也很容易适应管理内部内容区域。

为什么您的代码不起作用

加载程序将创建一个新的锚平面,但您永远不会将新窗格添加到场景图中的父窗格中

快速修复

而不是:

content = (AnchorPane) FXMLLoader.load("vista2.fxml");
写:

content.getChildren().setAll(FXMLLoader.load("vista2.fxml"));
用新vista替换内容子项。内容本身保留在场景图中,因此在设置其子对象时,同时也将它们附加到场景图中

您可能需要使用布局(例如,使用自动调整大小的布局,如堆叠窗格,而不是固定窗格),以获得您想要的确切行为

与其只是采用快速修复方法,我建议您查看下面链接的简单框架,因为这可能会为您提供一个更通用的机制,以获得您想要的行为

参考FXML导航框架

我创建了一个用于在主场景的一部分中交换fxml控制的内容窗格

该框架的机制与kithril的回答中建议的相同

  • 外部fxml的主窗格充当子窗格的支架
  • 外部fxml的主控制器提供了一个公共方法,可用于交换子窗格
  • 方便的导航器类是使用外部布局的主控制器静态初始化的
  • 导航器提供一个公共静态方法(通过调用主控制器上的方法)将新的子窗格加载到主容器中
  • 子窗格由各自的fxml加载程序在导航器中生成 为什么选择框架

    对于回答您的问题,该框架似乎有些过头了,也许是这样。然而,我发现与FXML相关的两个最常被问到的话题是:

  • FXML生成的窗格之间的导航(此问题)
  • 所以我觉得这个案例需要一个小的演示框架

    示例框架输出

    第一个屏幕显示显示第一个视景的应用程序布局。内容是在主应用程序布局中定义的标题和aliceblue颜色的可交换子内容窗格

    在下一个屏幕中,用户已导航到第二个视景,该视景保留主布局中的恒定标题,并用新的珊瑚色子内容窗格替换原始子窗格。新的子项已从新的fxml文件加载

    寻找更实质的东西吗?

    这是一个轻量级框架,它比这个问题中的示例框架更广泛、支持更好

    想找更简单的吗?

    只需调出场景根:

    其他选项?


    动画过渡和其他:

    我不确定这有多有效,但似乎很好,而且比上面的方法简单得多

    据我所知,这里发生的事情是这样的(它与应用程序类的Start()方法中发生的事情非常相似):

    然而,我不是一个java专家,而且对编程非常陌生,所以如果有经验的人能够对它进行评估,那将是一件好事

    编辑: 我找到了更简单的方法

    转到MainApplication类并使静态阶段成为parentWindow

    public static Stage parentWindow;
    @Override
    public void start(Stage stage) throws Exception {
        parentWindow = stage;
    
        Parent root = FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLMainScene.fxml"));
    
        Scene scene = new Scene(root);
    
        stage.setScene(scene);
        stage.show();
    }
    
    现在,您可以进入主舞台,以便在程序中的任何位置执行类似操作来更改场景:

        Parent window1;
        window1 = FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLWindow1.fxml"));
    
        //Scene newSceneWindow1 = new Scene(window1);
    
        Stage mainStage;
        //mainStage = (Stage)  ((Node)event.getSource()).getScene().getWindow();
        mainStage = MainApplication.parentWindow;
        mainStage.getScene().setRoot(newSceneWindow1); //we dont need to change whole sceene, only set new root.
    
    我的例子是

    使用:

    Main.getNavigation().load(View2.URL_FXML).Show();
    Main.getNavigation().GoBack();
    

    在这种情况下,我建议您改用。首先为内容创建自定义组件:

    class Content2 extends AnchorPane {
        Content() {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("vista2.fxml");
            loader.setRoot(this);
            loader.setController(this);
            loader.load();
        }
    }
    
    vista2.fxml
    文件根目录中的
    AnchorPane
    标记替换为
    fx:root

    <fx:root type="javafx.scene.layout.AnchorPane" xmlns:fx="http://javafx.com/fxml">
        ...
    </fx:root>
    
    最后,在java代码或fxml中绑定自定义事件处理程序:

    @FXML
    onNextButtonClick() {
        Content2 content2 = new Content2();
        content2.setOnPreviousButtonClick((event) -> {
            Content1 content1 = new Content1();
    
            layout.getChildren().clear();
            layout.getChildren().add(content1);
        });
    
        layout.getChildren().clear();
        layout.getChildren().add(content2);    
    }
    
    如果您不想动态添加内容,只需将
    setVisible()
    添加到
    true
    false

    就可以了 我尝试了大多数答案,但这不是我想要的,所以我只是用给出的理想来做这件事:

    public class Main extends Application {
    public static Stage homeStage;
    @Override
    public void start(Stage primaryStage) throws Exception{
        homeStage = primaryStage;
        Parent root = FXMLLoader.load(getClass().getResource("mainView.fxml"));
        root.getStylesheets().add(getClass().getResource("stylesheet/custom.css").toExternalForm());
        homeStage.setTitle("Classification of Living Organisms");
        homeStage.setScene(new Scene(root, 600, 500));
        homeStage.show();
    }
    
    
    public static void main(String[] args) {
        launch(args);
      }
    }
    
    这是我的主课。带有登录窗口/page mainView.fxml的Main.java。 在mainController.java类中使用了一点@Tomasz的想法,尽管在使用之前我有点困惑:

    public void gotoSubMenu(Event event) {
        Parent window1;
        try {
            window1 = FXMLLoader.load(getClass().getResource("src/displayView.fxml"));
            Stage window1Stage;
            Scene window1Scene = new Scene(window1, 600, 500);
            window1Stage = Main.homeStage;
            window1Stage.setScene(window1Scene);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    创建了一个名为“window1”的新父窗口,该窗口在src目录中加载了名为“displayView.fxml”的第二个fxml文件。 创建主视图阶段的对象,并将场景设置为根为window1的新创建场景。
    希望这对现在进入#JavaFX的人有所帮助。

    如果你想让按钮调用新的fxml文件,这对我来说很有用

    @FXML
    private void mainBClicked(ActionEvent event) throws IOException {
        Stage stage;
        Parent root;
        stage=(Stage) ((Button)(event.getSource())).getScene().getWindow();
        root = FXMLLoader.load(getClass().getResource("MainMenu.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }
    

    保持相同的场景容器,但更改场景容器内的视图

    假设要将新视图和控制器传递到的场景容器是名为sceneContainer的网格窗格布局

    建立新视图的FXMLLoader对象

    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Notifications.fxml"));
    
    创建一个匹配的容器
    @FXML
    private void mainBClicked(ActionEvent event) throws IOException {
        Stage stage;
        Parent root;
        stage=(Stage) ((Button)(event.getSource())).getScene().getWindow();
        root = FXMLLoader.load(getClass().getResource("MainMenu.fxml"));
        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }
    
    FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Notifications.fxml"));
    
    GridPane yourNewView = fxmlLoader.load();
    
    sceneContainer.getChildren().setAll(yourNewView);
    
    Notifications notifications = fxmlLoader.getController();
    notifications.passUserName(userName);
    
    @FXML
    public void setNotificationsViewToScene() {
    
        try {
             FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Notifications.fxml"));
             GridPane yourNewView = fxmlLoader.load();
             sceneContainer.getChildren().setAll(yourNewView);
    
             Notifications notifications = fxmlLoader.getController();
             notifications.passUserName(userName);
    
        } catch (IOException e) {
             e.printStackTrace();
        }
    }