JavaFX:如何在不关注主窗口的情况下关闭子窗口

Sai*_*dem 7 javafx javafx-2 javafx-8

我试图在一段时间后以编程方式关闭子窗口。此子窗口initOwner设置有主阶段。但是在关闭此子窗口时,主窗口将变得集中。有什么办法(以编程方式)关闭子窗口而不关注主窗口吗?

以下是我的问题的快速演示。我尝试了所有可能的方式来关闭窗口。重现步骤:

  1. 启动应用程序后,单击按钮以打开子窗口。此子窗口将在10秒后自动关闭。

  2. 同时打开任何其他应用程序(记事本,Outlook,浏览器..或其他)。在处理该应用程序时,当关闭子窗口时,主阶段将获得焦点并位于当前应用程序的前面。这对我的客户来说很烦。

注意:我无法删除initOwner(),因为我一直希望将子窗口保持在主窗口顶部。

更新:根据评论,我尝试在Windows 10中使用不同的jdk版本(u91,u121和u211)运行该演示。在所有这三种情况下,关闭子窗口的那一刻,主要阶段就来到了前面。我什至在不同的系统上尝试过,但结果是相同的:(

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:随附演示此问题的gif。 在此处输入图片说明

Ole*_*ndr 2

窗口如何获得焦点取决于平台(OS + JRE)。平台处理焦点窗口,这就是为什么窗口在调用焦点请求后可能在不同操作系统上有不同的行为。

由于您设置的限制,无法使用纯 JFX 实现所需的行为:

注意:我无法删除 initOwner(),因为我总是希望将子窗口保留在主窗口顶部。

com.sun.javafx.tk.quantum.WindowStage

if (!isPopupStage && owner != null && owner instanceof WindowStage) {
    WindowStage ownerStage = (WindowStage)owner;
    ownerStage.requestToFront();
}
Run Code Online (Sandbox Code Playgroud)

你能做的就是模仿owner window <- child window关系而不初始化真正的所有者。

来源:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

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();
    }));
Run Code Online (Sandbox Code Playgroud)

或者,您可以结合 JFX 和 SWING 来过滤焦点事件,但您将面临纯粹的架构邪恶:)