Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX : How to close a sub window without getting focus on main window

I am trying to close a sub window programatically after certain time. This sub window initOwner is set with main stage. But on closing this sub window, the main window is getting focused. Is there any way to close the sub window(programatically) without gaining focus on main window?

Below is the quick demo of my issue. I tried all the possible ways to close the window. Steps to reproduce:

  1. After starting the application, click the button to open the sub window. This sub window will close automatically after 10seconds.

  2. Meanwhile open any other application (notepad, outlook, browser.. or whatever). While you are working on that application, when the sub window is closed, the main stage gets focus and comes in front of my current application. This is quite annoying to my client.

Note: I cannot remove initOwner(), as I always want to keep my sub window on top of the main window.

Update : Based on the comments, I tried running the demo with different jdk versions (u91, u121 & u211) and in Windows 10. In all three cases , the moment the sub window is closed, the main stage is coming to front. I even tried in a differnt system but the results are same :(

import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Duration;

public class OwnerStage_Demo extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Button button = new Button("Open Window");
        button.setOnAction(e -> {
            Stage stg = new Stage();
            stg.setScene(new Scene(new StackPane(), 300, 300));
            stg.initOwner(stage);
            stg.show();
            // Window will close automatically after 10secs.
            Timeline timeline = new Timeline(new KeyFrame(Duration.millis(10000), x -> {
                //stg.close();
                //stg.hide();
                stg.fireEvent(new WindowEvent(stg, WindowEvent.WINDOW_CLOSE_REQUEST));
            }));
            timeline.setCycleCount(1);
            timeline.play();
        });
        VBox root = new VBox(button);
        root.setSpacing(10);
        Scene sc = new Scene(root, 600, 600);
        stage.setScene(sc);
        stage.show();
    }

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

Update : Attached the gif demonstrating the issue. enter image description here

like image 215
Sai Dandem Avatar asked Jul 02 '19 00:07

Sai Dandem


People also ask

How do you close a JavaFX stage?

Be default, to quit the program is to let the user click the standard window close button, typically represented by an X in the upper-right corner of the window's title bar.

How do I create a new JavaFX window?

javafx Windows Creating a new Window // create sample content Rectangle rect = new Rectangle(100, 100, 200, 300); Pane root = new Pane(rect); root. setPrefSize(500, 500); Parent content = root; // create scene containing the content Scene scene = new Scene(content); Stage window = new Stage(); window.

Which method is used to make a JavaFX stage visible?

Stage Modality The start() method is executed when the JavaFX application is launched (first main() is called which calls launch() which later calls start() ). Notice also, how a new JavaFX Stage object is created, its modality mode set, and then both the primary and the new Stage objects are made visible (shown).

What is window in JavaFX?

A top level window within which a scene is hosted, and with which the user interacts. A Window might be a Stage , PopupWindow , or other such top level. A Window is used also for browser plug-in based deployments.

How to close a JavaFX application on window close?

- Stack Overflow How to close a JavaFX application on window close? In Swing you can simply use setDefaultCloseOperation () to shut down the entire application when the window is closed. However in JavaFX I can't find an equivalent. I have multiple windows open and I want to close the entire application if a window is closed.

How do I create a window in JavaFX?

In JavaFX, to create a window, you use Stage class. There are three modelities that you can apply to the Stage through the stage.initModality (Modelity) method. When creating a new Stage, you can set up a parent window for it (also called the window owning it), via the stage.initOwner (parentStage) method​​​​​​​.

What happens when I Close a sub window?

This sub window will close automatically after 10seconds. Meanwhile open any other application (notepad, outlook, browser.. or whatever). While you are working on that application, when the sub window is closed, the main stage gets focus and comes in front of my current application.

What is JavaFX undecorated window?

The JavaFX undecorated window gives you a blank canvas, giving freedom to how your window looks without having to accept the default Windows title bar and buttons such as the Minimize, Maximise and Close buttons.


1 Answers

How a window gains the focus depends on a platform (OS + JRE). The platform processes focused window that is why the window may have different behavior on different OS after calling focus request.

There is no way to achieve required behaviour with pure JFX because of the restriction you had set:

Note: I cannot remove initOwner(), as I always want to keep my sub window on top of the main window.

com.sun.javafx.tk.quantum.WindowStage

if (!isPopupStage && owner != null && owner instanceof WindowStage) {
    WindowStage ownerStage = (WindowStage)owner;
    ownerStage.requestToFront();
}

What you can do is to imitate owner window <- child window relationship without initializing real owner.

Source:

public class PlainZStage extends Stage {

    public PlainZStage(final Window owner) {
        init(owner, this::focusedChanged);
    }

    private void init(final Window owner, final ChangeListener<Boolean> listener) {
        showingProperty().addListener(new ChangeListener<Boolean>() {
            @Override
            public void changed(final ObservableValue<? extends Boolean> observable, final Boolean oldValue,
                    final Boolean newValue) {
                owner.getScene().getRoot().setDisable(newValue);
                if (newValue) {
                    owner.focusedProperty().addListener(listener);
                } else {
                    owner.focusedProperty().removeListener(listener);
                    showingProperty().removeListener(this);
                }
            }
        });
    }

    private void focusedChanged(final ObservableValue<? extends Boolean> source, final Boolean oldValue,
            final Boolean newValue) {
        if (newValue && isShowing()) {
            toFront();
        }
    }
}

Usage:

button.setOnAction(e -> {
    final Stage stg = new PlainZStage(stage);
    stg.setScene(new Scene(new StackPane(), 300, 300));
    stg.show();
    // Window will close automatically after 10secs.
    final Timeline timeline = new Timeline(new KeyFrame(Duration.millis(10000), x -> {
        stg.close();
    }));

Alternatively, you could combine JFX&SWING to filter focus events but you will face pure architectural evil :)

like image 186
Oleks Avatar answered Sep 22 '22 00:09

Oleks