Mateus Viccari
Mateus Viccari

Reputation: 7709

How to get the current opened stage in JavaFX?

Is there a way to get the current opened Stage in JavaFX, if there is one open?

Something like this:

Stage newStage = new Stage();
newStage.initOwner(JavaFx.getCurrentOpenedStage()); //Like this

Upvotes: 19

Views: 44664

Answers (4)

Adam
Adam

Reputation: 36703

Java 9 makes this possible by the addition of the javafx.stage.Window.getWindows() method. Therefore you can just get list of Windows and see which are showing

List<Window> open = Stage.getWindows().stream().filter(Window::isShowing);

Upvotes: 18

Nelio Alves
Nelio Alves

Reputation: 1371

If you need the current stage reference inside an event handler method, you can get it from the ActionEvent param. For example:

    @FXML
    public void OnButtonClick(ActionEvent event) {

        Stage stage = (Stage)((Node) event.getSource()).getScene().getWindow();

       (...)
    }

You can also get it from any control declared in your controller:

@FXML
private Button buttonSave;

(...)    

Stage stage = (Stage) buttonSave.getScene().getWindow();

Upvotes: 19

Salman Saleh
Salman Saleh

Reputation: 185

You can create a label in your java fxml.

Then in your controller class refer your label like this :

@FXML private Label label;

Then in any function of the controller class you can access the current stage by this block of code :

private void any_function(){
        Stage stage;
        stage=(Stage) label.getScene().getWindow();
}

Upvotes: 8

James_D
James_D

Reputation: 209330

There's no built-in functionality for this. In most use cases, you open a new Stage as a result of user action, so you can call getScene().getWindow() on the node on which the action occurred to get the "current" window.

In other use cases, you will have to write code to track current windows yourself. Of course, multiple windows might be open, so you need to track them in some kind of collection. I'd recommend creating a factory class to manage the stages and registering event handlers for the stages opening and closing, so you can update a property and/or list. You'd probably want this to be a singleton. Here's a sample implementation: here getOpenStages() gives an observable list of open stages - the last one is the most recently opened - and currentStageProperty() gives the focused stage (if any). Your exact implementation might be different, depending on your exact needs.

public enum StageFactory {
    INSTANCE ;

    private final ObservableList<Stage> openStages = FXCollections.observableArrayList();

    public ObservableList<Stage> getOpenStages() {
        return openStages ;
    }

    private final ObjectProperty<Stage> currentStage = new SimpleObjectProperty<>(null);
    public final ObjectProperty<Stage> currentStageProperty() {
        return this.currentStage;
    }
    public final javafx.stage.Stage getCurrentStage() {
        return this.currentStageProperty().get();
    }
    public final void setCurrentStage(final javafx.stage.Stage currentStage) {
        this.currentStageProperty().set(currentStage);
    }

    public void registerStage(Stage stage) {
        stage.addEventHandler(WindowEvent.WINDOW_SHOWN, e -> 
                openStages.add(stage));
        stage.addEventHandler(WindowEvent.WINDOW_HIDDEN, e -> 
                openStages.remove(stage));
        stage.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
            if (isNowFocused) {
                currentStage.set(stage);
            } else {
                currentStage.set(null);
            }
        });
    }

    public Stage createStage() {
        Stage stage = new Stage();
        registerStage(stage);
        return stage ;
    }

}

Note this only allows you to track stages obtained from StageFactory.INSTANCE.createStage() or created elsewhere and passed to the StageFactory.INSTANCE.registerStage(...) method, so your code has to collaborate with that requirement. On the other hand, it gives you the chance to centralize code that initializes your stages, which may be otherwise beneficial.

Here's a simple example using this:

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class SceneTrackingExample extends Application {

    int count = 0 ;

    @Override
    public void start(Stage primaryStage) {
        StageFactory factory = StageFactory.INSTANCE ;
        factory.registerStage(primaryStage);

        configureStage(primaryStage);
        primaryStage.show();
    }

    private void configureStage(Stage stage) {
        StageFactory stageFactory = StageFactory.INSTANCE;
        Stage owner = stageFactory.getCurrentStage() ;
        Label ownerLabel = new Label();
        if (owner == null) {
            ownerLabel.setText("No owner");
        } else {
            ownerLabel.setText("Owner: "+owner.getTitle());
            stage.initOwner(owner);
        }
        stage.setTitle("Stage "+(++count));
        Button newStage = new Button("New Stage");
        newStage.setOnAction(e -> {
            Stage s = stageFactory.createStage();
            Stage current = stageFactory.getCurrentStage() ;
            if (current != null) {
                s.setX(current.getX() + 20);
                s.setY(current.getY() + 20);
            }
            configureStage(s);
            s.show();
        });

        VBox root = new VBox(10, ownerLabel, newStage);
        root.setAlignment(Pos.CENTER);
        stage.setScene(new Scene(root, 360, 150));
    }

    public enum StageFactory {
        INSTANCE ;

        private final ObservableList<Stage> openStages = FXCollections.observableArrayList();

        public ObservableList<Stage> getOpenStages() {
            return openStages ;
        }

        private final ObjectProperty<Stage> currentStage = new SimpleObjectProperty<>(null);
        public final ObjectProperty<Stage> currentStageProperty() {
            return this.currentStage;
        }
        public final javafx.stage.Stage getCurrentStage() {
            return this.currentStageProperty().get();
        }
        public final void setCurrentStage(final javafx.stage.Stage currentStage) {
            this.currentStageProperty().set(currentStage);
        }

        public void registerStage(Stage stage) {
            stage.addEventHandler(WindowEvent.WINDOW_SHOWN, e -> 
                    openStages.add(stage));
            stage.addEventHandler(WindowEvent.WINDOW_HIDDEN, e -> 
                    openStages.remove(stage));
            stage.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
                if (isNowFocused) {
                    currentStage.set(stage);
                } else {
                    currentStage.set(null);
                }
            });
        }

        public Stage createStage() {
            Stage stage = new Stage();
            registerStage(stage);
            return stage ;
        }

    }

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

Upvotes: 11

Related Questions