我有2个fxml文件:
我想知道如何在“Master”场景中加载内容空间中的第二个文件。在javaFX中工作是一件好事还是加载新场景更好?
我正在尝试做这样的事情,但它不起作用:
@FXML
private AnchorPane content;
@FXML
private void handleButtonAction(ActionEvent event) {
content = (AnchorPane) FXMLLoader.load("vista2.fxml");
}
感谢您的帮助。
答案 0 :(得分:64)
为什么您的代码不起作用
加载程序会创建一个新的AnchorPane,但您永远不会将新窗格添加到场景图中的父窗格。
快速修复
而不是:
content = (AnchorPane) FXMLLoader.load("vista2.fxml");
写:
content.getChildren().setAll(FXMLLoader.load("vista2.fxml"));
用新视图替换内容子项。内容本身保留在场景图中,因此当您设置它的子项时,您也会同时将它们附加到场景图中。
您可能需要使用布局(例如,使用自动调整大小布局(如StackPanes而不是AnchorPanes)来获得所需的确切行为。
我建议不要仅采用快速修复,而是检查下面链接的简单框架,因为它可能会为您提供更通用的机制来获取您想要的行为。
参考FXML导航框架
我创建了一个small framework,用于在主场景的一部分内外交换fxml控制的内容窗格。
框架的机制与kithril的回答中提出的相同。
为何选择框架
这个框架对于回答你的问题似乎有些过分,也许就是这样。但是,我发现与FXML有关的两个最常见的主题是:
所以我觉得这个案例需要一个小的演示框架。
示例框架输出
第一个屏幕显示显示第一个视景的应用程序布局。内容是在主应用程序布局中定义的标题和aliceblue彩色可互换的子内容窗格。
在下一个屏幕中,用户已导航到第二个视景,该视图保留主要布局中的常量标题,并用新的珊瑚色子内容窗格替换原始子窗格。新子项已从新的fxml文件加载。
寻找更重要的东西?
这个问题的示例框架比afterburner.fx更广泛,更受支持的轻量级框架。
寻找更简单的东西?
只需换出场景根:Changing Scenes in JavaFX。
其他选项?
动画过渡和其他:Switch between panes in JavaFX
答案 1 :(得分:5)
我不确定这是多么有效,但似乎很好,而且对于上述方法来说更简单,更简单。
https://www.youtube.com/watch?v=LDVztNtJWOo
据我所知,这里发生了什么(它与应用程序类中Start()方法的内容非常类似):
private void buttonGoToWindow3Action(ActionEvent event) throws IOException{
Parent window3; //we need to load the layout that we want to swap
window3 = (StackPane)FXMLLoader.load(getClass().getResource("/ScenePackage/FXMLWindow3"));
Scene newScene; //then we create a new scene with our new layout
newScene = new Scene(window3);
Stage mainWindow; //Here is the magic. We get the reference to main Stage.
mainWindow = (Stage) ((Node)event.getSource()).getScene().getWindow();
mainWindow.setScene(newScene); //here we simply set the new scene
}
然而,我不是一名java专家,对编程很新,所以如果有经验的人会对它进行评估会很好。
编辑: 我发现了更简单的方法;
转到MainApplication类并创建静态Stage 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.
答案 2 :(得分:0)
其他人可能有更好的解决方案,但我的解决方案是在外部fxml中有一个像VBox这样的简单容器,然后加载新内容并将其添加为容器的子容器。如果您只加载一个或两个表单,这可能是最佳选择。但是,对于一个更完整的框架,我发现这篇博文有用:https://blogs.oracle.com/acaicedo/entry/managing_multiple_screens_in_javafx1她有她的框架的源代码,其中包括花哨的过渡。虽然它旨在管理顶级场景,但我发现它也很容易适应管理内部内容区域。
答案 3 :(得分:0)
答案 4 :(得分:0)
在这种情况下,我建议您改用custom component。首先为您的内容创建自定义组件:
class Content2 extends AnchorPane {
Content() {
FXMLLoader loader = new FXMLLoader(getClass().getResource("vista2.fxml");
loader.setRoot(this);
loader.setController(this);
loader.load();
}
}
使用AnchorPane
替换vista2.fxml
文件根目录中的fx:root
标记:
<fx:root type="javafx.scene.layout.AnchorPane" xmlns:fx="http://javafx.com/fxml">
...
</fx:root>
然后,您只需使用自定义事件绑定和箭头功能即可完成此操作。将事件处理程序属性添加到Content
类:
private final ObjectProperty<EventHandler<ActionEvent>> propertyOnPreviousButtonClick = new SimpleObjectProperty<EventHandler<ActionEvent>>();
@FXML
private void onPreviousButtonClick(ActionEvent event) {
propertyOnPreviousButtonClick.get().handle(event)
}
public void setOnPreviousButtonClick(EventHandler<ActionEvent> handler) {
propertyOnPreviousButtonClick.set(handler);
}
最后,在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
答案 5 :(得分:0)
也陷入困境 试过大部分答案,不是我想要的,所以我只是用了理想来做到这一点:
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);
}
}
这是我的主要课程。带着陆窗口/页面mainView.fxml的Main.java。
使用了一些@Tomasz的想法,虽然在我在mainController.java类中执行此操作之前让我感到困惑:
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();
}
}
创建了一个名为&#39; window1&#39;的新父窗口。加载了名为&#39; displayView.fxml&#39;的第二个fxml文件。在src目录中。 创建了主视图阶段的对象,并将场景设置为新创建的场景,其根目录为window1。 希望这有助于现在进入#JavaFX的人。
答案 6 :(得分:0)
如果您正在寻找一种方法让按钮调用新的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();
}
答案 7 :(得分:0)
保留相同的场景容器,但更改场景容器内的视图...
说要传递新视图和控制器到的场景容器是一个名为sceneContainer的GridPane布局。
建立新视图的FXMLLoader对象。
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Notifications.fxml"));
创建一个匹配的容器并将新视图的内容加载到其中。
GridPane yourNewView = fxmlLoader.load();
将新视图设置为sceneContainer。 (setAll首先清除所有子级)
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();
}
}