Sai Dandem
Sai Dandem

Reputation: 9914

JavaFX : How to manage the z-index of stages

Is there any way to manage the z-index ordering of multiple stages (independent to each other). Something like, say there are three Stages A, B & C. StageA should stay always at back. StageB should be in middle and StageC should be always on top. Just a special note that these three stages have no relation to each other (like owner)

Below is a quick demo of what I am expecting. I need to access any stage (for dragging or modifying) but z-order need to be maintained. Any ideas or help is highly appreciated.

import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

import java.util.HashMap;
import java.util.Map;

public class StagesZOrdering_Demo extends Application {
    private Map<String, Stage> stages = new HashMap<>();

    @Override
    public void start(Stage stage) throws Exception {
        Button button1 = new Button("Back");
        button1.setOnAction(e -> openStage("Back"));

        Button button2 = new Button("Middle");
        button2.setOnAction(e -> openStage("Middle"));

        Button button3 = new Button("Front");
        button3.setOnAction(e -> openStage("Front"));

        VBox root = new VBox(button1, button2, button3);
        root.setAlignment(Pos.CENTER);
        root.setSpacing(10);
        Scene sc = new Scene(root, 200, 200);
        stage.setScene(sc);
        stage.show();
    }

    private void openStage(String title) {
        if (stages.get(title) != null) {
            stages.get(title).requestFocus();
        } else {
            Stage stg = new Stage();
            stg.setTitle(title);
            stg.setScene(new Scene(new StackPane(), 300, 300, Color.GRAY));
            stg.show();
            stg.setOnHidden(e -> stages.remove(title));
            stages.put(title, stg);
        }
    }

    public static void main(String... a) {
        Application.launch(a);
    }
}

Upvotes: 7

Views: 1379

Answers (1)

c0der
c0der

Reputation: 18792

The following mcve demonstrates re-ordering of back-to-front stages, once a ROOT MOUSE_EXITED_TARGET event is fired from one of them.
It is a simple yet limited solution:

import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventType;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class StagesZOrdering_Demo extends Application {

    public enum STAGES {BACK, MIDDLE, FRONT;}
    private final EnumMap<STAGES, Stage> stages = new EnumMap<>(STAGES.class);

    @Override
    public void start(Stage stage) throws Exception {

        VBox root = new VBox();
        for(STAGES s : STAGES.values()){
            Button button = new Button(s.name());
            button.setOnAction(e -> openStage(s));
            root.getChildren().add(button);
        }

        root.setAlignment(Pos.CENTER);
        root.setSpacing(10);
        Scene sc = new Scene(root, 200, 200);
        stage.setScene(sc);
        stage.show();
    }

    private void openStage(STAGES s) {
        if (stages.get(s) == null) {
            Stage stg = new Stage();
            stg.setTitle(s.name());
            stg.addEventHandler(EventType.ROOT, e->reOrder(e));
            stg.setScene(new Scene(new StackPane(), 300, 100, Color.GRAY));
            stg.show();
            stg.setOnHidden(e -> stages.remove(s));
            stages.put(s, stg);
        }
    }

    private void reOrder(Event e){
        if(! e.getEventType().getName().equals("MOUSE_EXITED_TARGET"))
            return;

        for(STAGES s : STAGES.values()){
            Stage stage = stages.get(s);
            if(stage != null) {
                stage.requestFocus();
            }
        }
    }

    public static void main(String... a) {
        Application.launch(a);
    }
}

enter image description here

Upvotes: 2

Related Questions