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

时间:2017-02-23 13:11:28

标签: java javafx

我正在尝试解决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()会消除这种行为。

现在我的问题是:我有多个" popups"有共同所有者(主要阶段)。在initOwner()解决方法之后,将鼠标悬停在主要舞台上的控件上不会导致任何意外行为。如果您将鼠标悬停在弹出窗口中的控件上而另一个弹出窗口处于焦点位置,则悬停的弹出窗口将会隐藏焦点。

有没有办法可以解决这个错误,不仅是主要阶段,还有弹出窗口?

更新:原来我的解决方法有不良副作用。舞台状态的Javadocs跟随:

  

舞台将始终位于其父窗口之上。

另外,什么是一种解决方法,使得弹出窗口不会始终位于顶部"并且可以最小化?

4 个答案:

答案 0 :(得分:4)

有一种方法可以通过覆盖StackPanes来绕过它。使用Scene创建StackPane,以便在舞台失去焦点时添加另一个StackPane。覆盖窗格将阻止Tooltip或鼠标悬停时发生的任何其他事件,而窗格不在焦点上。您也可以最小化您的任何阶段,并且它们不会始终处于最佳状态。

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

答案 1 :(得分:3)

你可以试试这个:

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

答案 2 :(得分:2)

我已经提出了这个替代解决方案,因为我发现在我的情况下更容易继承Tooltip并在那里应用修复。我只是重载show()方法,只显示拥有窗口是否被聚焦。它对我来说就像一个魅力...

public class FixedTooltip extends Tooltip {

    public FixedTooltip(String string) {
        super(string);
    }

    @Override
    protected void show() {        
        Window owner = getOwnerWindow();        
        if (owner.isFocused())
            super.show(); 
    }    

}

答案 3 :(得分:1)

只要节点的窗口失去焦点,您就可以尝试取消设置工具提示。如下:

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

    public static void installTooltip(Node n, Tooltip tp)
    {
        Window w = n.getScene().getWindow();
        w.focusedProperty().addListener((val, before, after) -> {
            if (after)
                Tooltip.install(n, tp);
            else
                Tooltip.uninstall(n, tp);
        });

        if (w.isFocused())
            Tooltip.install(n, tp);
        else
            Tooltip.uninstall(n, tp);
    }

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

        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();
        primaryStage.show();

        installTooltip(btn, tp);
    }
}

当然,在将节点添加到组件后,您必须调用installTooltip