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

时间:2019-07-02 00:17:19

标签: javafx javafx-8 javafx-2

我试图在一段时间后以编程方式关闭子窗口。此子窗口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);
    }
}

更新:附加了演示问题的gif。 enter image description here

1 个答案:

答案 0 :(得分:1)

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

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

  

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

com.sun.javafx.tk.quantum.WindowStage

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

您可以做的是模仿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();
        }
    }
}

用法:

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();
    }));

或者,您可以结合使用JFX&SWING来过滤焦点事件,但是您将面临纯粹的体系结构弊端:)