在javafx中显示工具提示会将其舞台置于前台

2022-09-03 15:11:31

我正在尝试解决jdk中的这个错误:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8088624

public class Blubb extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Button btn = new Button("Click");
        btn.setTooltip(new Tooltip("Blubb"));

        Scene scene = new Scene(new BorderPane(btn), 320, 240);
        primaryStage.setScene(scene);
        primaryStage.show();

        Stage secondStage = new Stage();
        secondStage.setScene(new Scene(new BorderPane(new Button("Click")), 320, 240));
        //secondStage.initOwner(primaryStage);
        secondStage.show();
    }
}

如果将主舞台上的按钮悬停在首位,它将出现在第二阶段的前面。我发现调用舞台将消除这种行为。initOwner()

现在我的问题是:我有多个“弹出窗口”,它们有一个共同的所有者(主要阶段)。将鼠标悬停在主阶段的控件上不会在解决方法后导致任何意外行为。但是,如果将鼠标悬停在弹出窗口中的控件上,而另一个弹出窗口处于焦点中,则悬停的弹出窗口将窃取焦点。initOwner()

有没有办法解决这个错误,不仅在主要阶段,而且在弹出窗口?

更新:事实证明我的解决方法有不希望的副作用。Javadocs for Stage state follow:

舞台将始终位于其父窗口的顶部。

那么另外,有什么解决方法可以使弹出窗口“总是在顶部”并且可最小化?


答案 1

有一种方法可以通过覆盖StackPanes来绕过它。创建您的 with a,以便在舞台失去焦点时可以添加另一个。覆盖窗格将防止在窗格未聚焦时鼠标悬停时发生 s 或其他任何情况。您还可以最小化任何阶段,它们不会总是在顶部。SceneStackPaneStackPaneTooltip

public class Blubb extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Button button_1 = new Button("Button #1");
        button_1.setTooltip(new Tooltip("Blubb #1"));

        StackPane primary = new StackPane(new BorderPane(button_1));
        primaryStage.setScene(new Scene(primary, 320, 240));
        addStageFocusListener(primaryStage, primary);
        primaryStage.show();

        Button button_2 = new Button("Button #2");
        button_2.setTooltip(new Tooltip("Blubb #2"));

        StackPane second = new StackPane(new BorderPane(button_2));
        Stage secondStage = new Stage();
        addStageFocusListener(secondStage, second);
        secondStage.setScene(new Scene(second, 320, 240));
        secondStage.show();
    }

    public void addStageFocusListener(Stage stage, StackPane stackPane) {
        stage.focusedProperty().addListener(new ChangeListener<Boolean>(){
            public final StackPane preventTooltip = new StackPane();
            public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                if(stage.isFocused()) {
                    if(stackPane.getChildren().contains(preventTooltip)) {
                        stackPane.getChildren().remove(preventTooltip);
                    }
                } else {
                    stackPane.getChildren().add(preventTooltip);
                }
            }
        });
    }
}

答案 2

你可以试试这个:

public static final disableMouseEventOnUnfocus(final Stage stage)
{
    if (stage == null
        || stage.getScene() == null
        || stage.getScene().getRoot() == null)
        return;
    else
    {
        stage.getScene().getRoot().mouseTransparentProperty().bind(stage.focusedProperty().not());
    }
}

我没有尝试过,但如果它有效,这应该是一个不错的选择。无需重构布局,并且可以将所有布局保留在 FXML 中,而无需指定工具提示。fx:id


推荐