Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the current opened stage in JavaFX?

Tags:

java

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
like image 305
Mateus Viccari Avatar asked Oct 03 '15 12:10

Mateus Viccari


People also ask

What method is invoked to display a stage in JavaFX?

Showing a Stage The difference between the JavaFX Stage methods show() and showAndWait() is, that show() makes the Stage visible and the exits the show() method immediately, whereas the showAndWait() shows the Stage object and then blocks (stays inside the showAndWait() method) until the Stage is closed.

What does JavaFX stage stage do?

A Stage in JavaFX is a top-level container that hosts a Scene, which consists of visual elements. The Stage class in the javafx. stage package represents a stage in a JavaFX application. The primary stage is created by the platform and passed to the start(Stage s) method of the Application class.


4 Answers

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);
like image 162
Adam Avatar answered Sep 20 '22 01:09

Adam


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();
like image 35
Nelio Alves Avatar answered Sep 24 '22 01:09

Nelio Alves


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);
    }
}
like image 31
James_D Avatar answered Sep 21 '22 01:09

James_D


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();
}
like image 42
Salman Saleh Avatar answered Sep 20 '22 01:09

Salman Saleh