Search code examples
titlefxmlstagescene

JavaFX Using alternative FXML structure for Title (Stage is root)


I read answer about putting Title in FXML (JavaFx : Set window title in fxml file), but I don't understand how to call this code.

I can't call it in the classic way:

FXMLLoader loader = new FXMLLoader(getClass().getResource("some.fxml"));
Scene scene = new Scene(loader.load());
Stage stage = new Stage();
stage.initOwner(root.getScene().getWindow());
stage.initModality(Modality.WINDOW_MODAL);
stage.setScene(scene);
stage.show();

some.fxml

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

<?import javafx.scene.layout.VBox?>
<?import javafx.stage.Stage?>
<?import javafx.scene.Scene?>
<?import javafx.scene.control.Label?>

<Stage title="Some Stage">
  <scene>
    <Scene>
      <VBox xmlns:fx="http://javafx.com/fxml">
        <children>
          <Label text="John Doe"/>
        </children>
      </VBox>
    </Scene>
  </scene>
</Stage>

Solution

  • Because the fxml is creating a stage, you don't need to create another stage in your Java code, just get a reference to the stage created by FXML and show it directly.

    titled stage via fxml

    StageLoader.java

    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.layout.StackPane;
    import javafx.stage.*;
    
    import java.io.IOException;
    
    public class StageLoader extends Application {
    
        private void showDialog(Stage owner) {
            try {
                FXMLLoader loader = new FXMLLoader(
                        getClass().getResource("some.fxml")
                );
                Stage dialog = loader.load();
                dialog.initOwner(owner);
                dialog.initModality(Modality.WINDOW_MODAL);
                dialog.initStyle(StageStyle.UTILITY);
                dialog.show();
            } catch (IOException e) {
                System.out.println("Unable to load dialog FXML");
                e.printStackTrace();
            }
        }
    
        @Override
        public void start(final Stage stage) throws IOException {
            Button openDialog = new Button("Open Dialog");
            openDialog.setOnAction(event -> showDialog(stage));
    
            stage.setTitle("Main Window");
            stage.setScene(
                    new Scene(
                            new StackPane(openDialog),
                            200, 200
                    )
            );
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    I made a couple of minor modifications to the fxml to ensure the resultant stage is large enough to actually see the dialog stage title.

    some.fxml

    <?xml version="1.0" encoding="utf-8"?>
    
    <?import javafx.scene.layout.VBox?>
    <?import javafx.stage.Stage?>
    <?import javafx.scene.Scene?>
    <?import javafx.scene.control.Label?>
    
    <Stage title="Some Stage" resizable="false" xmlns:fx="http://javafx.com/fxml" >
      <scene>
        <Scene>
          <VBox >
            <children>
              <Label text="John Doe" prefWidth="150"/>
            </children>
          </VBox>
        </Scene>
      </scene>
    </Stage>
    

    SceneBuilder who can't open FXML after adding Stage and Scene tags.

    You could write the FXML with the stage and scene definitions as an outer shell with an embedded <fx:include..> statement to include an inner FXML document which could be opened edited directly in SceneBuilder. Also, you could create a feature request against SceneBuilder (it is called the "design tool" in the issue tracker), to request direct support for FXML files with stage roots and scenes included in the FXML.