我试图在一段时间后以编程方式关闭子窗口。此子窗口initOwner设置有主阶段。但是在关闭此子窗口时,主窗口将变得集中。有什么办法(以编程方式)关闭子窗口而不关注主窗口吗?
以下是我的问题的快速演示。我尝试了所有可能的方式来关闭窗口。重现步骤:
启动应用程序后,单击按钮以打开子目录 窗口。此子窗口将在10秒后自动关闭。
同时打开任何其他应用程序(记事本,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);
}
}
答案 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来过滤焦点事件,但是您将面临纯粹的体系结构弊端:)