0

I am currently migrating all my .form files over to .fxml and I'm having a bit trouble loading another page within the same window.

With .form method I was able to establish a card layout and switch it within that.

What I would do is create a card layout and have the forms load in there.

I created a few test .fxml and some basic code. It loads the second one but in a new window and I'm trying to avoid that and load it within the same window.

index.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 maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="480.0" prefWidth="320.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Test">
   <children>
      <Button id="btnbuy" fx:id="btnbuy" layoutX="134.0" layoutY="2.0" mnemonicParsing="false" onAction="#loadSecondFxml" text="Purchase" />
      <Button id="btnSell" fx:id="btnsell" layoutX="140.0" layoutY="454.0" mnemonicParsing="false" text="Sell" />
   </children>
</AnchorPane>

MainPage.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 maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="480.0" prefWidth="320.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Test">
   <children>
      <Pane layoutX="6.0" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="480.0" prefWidth="320.0">
         <children>
            <Label layoutX="146.0" layoutY="232.0" text="You got here" />
         </children></Pane>
   </children>
</AnchorPane>

Test.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;

public class Test extends Application {
    private MainPage parentForm;
    //private Panel panel;
    public Button btnbuy;
    public Button btnsell;

    public Test(){
    }
    public void start(Stage primaryStage) throws Exception{
        Parent root = FXMLLoader.load(getClass().getResource("Index.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 320, 480));
        primaryStage.show();
    }
    public void loadSecondFxml() throws Exception{
        Stage primaryStage = new Stage();
        Parent root = FXMLLoader.load(getClass().getResource("MainPage.fxml"));
        primaryStage.setTitle("Hi");
        primaryStage.setScene(new Scene(root, 320, 480));
        primaryStage.show();
    }

    public static void main(String args[]){
        launch(args);
    }
}

I know it has something to do with the setscene portion. But I'm having trouble trying to get the syntax right.

Zoe
  • 27,060
  • 21
  • 118
  • 148
BTCDude
  • 31
  • 7

1 Answers1

3

There are multiple ways of doing this. Which one works best for you depends on your needs:

Replacing the root

By replacing the root you can replace all the contents shown in a window.

@Override
public void start(Stage primaryStage) {
    final Region r1 = new Region();
    r1.setStyle("-fx-background-color: yellow;");

    final Region r2 = new Region();
    r2.setStyle("-fx-background-color: blue;");

    final Scene scene = new Scene(r1);
    scene.setOnMouseClicked(evt -> {
        scene.setRoot(scene.getRoot() == r1 ? r2 : r1); // swap roots
    });

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

Modifying part of the scene

By modifying a parent in the scene you can change the display.

BorderPane

This layout allows you to easily replace it's (up to) 5 nodes:

@Override
public void start(Stage primaryStage) {
    final Region r1 = new Region();
    r1.setStyle("-fx-background-color: yellow;");

    final Region r2 = new Region();
    r2.setStyle("-fx-background-color: blue;");

    final BorderPane root = new BorderPane(r1);

    Button btn = new Button("swap");
    btn.setOnAction(evt -> {
        root.setCenter(root.getCenter() == r1 ? r2 : r1);
    });

    root.setTop(btn);

    final Scene scene = new Scene(root, 400, 400);

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

Modifying the child list of some other layout

This can be a bit more complex than using BorderPane, but Panes and Group allow you to modify the children list to modify the layout:

@Override
public void start(Stage primaryStage) {
    final Region r1 = new Region();
    r1.setStyle("-fx-background-color: yellow;");
    VBox.setVgrow(r1, Priority.ALWAYS);

    final Region r2 = new Region();
    r2.setStyle("-fx-background-color: blue;");
    VBox.setVgrow(r2, Priority.ALWAYS);

    final VBox root = new VBox();

    Button btn = new Button("swap");
    btn.setOnAction(evt -> {
        root.getChildren().set(1, root.getChildren().get(1) == r1 ? r2 : r1);
    });

    root.getChildren().addAll(btn, r1);

    final Scene scene = new Scene(root, 400, 400);

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

Something like TabPane may also suit your needs.

Using something like this with fxmls requires you to provide access to the object managing the replacement. You can read about this topic here: Passing Parameters JavaFX FXML

You shouldn't use the Application class as controller class though. This violates the single responsibility principle. Also you create a new instance of the class every time a fxml with the class specified as value of the fx:controller attribute is loaded. The Application class is supposed to be the "entry point" of your program.

fabian
  • 80,457
  • 12
  • 86
  • 114