【问题标题】:displaying a tooltip in javafx brings its stage into the foreground在 javafx 中显示工具提示会将其舞台置于前台
【发布时间】:2017-07-13 23:49:32
【问题描述】:

我正在尝试解决 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 如下:

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

那么另外,有什么解决方法可以使弹出窗口不“始终位于顶部”和最小化?

【问题讨论】:

    标签: java javafx


    【解决方案1】:

    有一种方法可以通过覆盖 StackPanes 来绕过它。使用StackPane 创建您的Scene,以便在舞台失去焦点时添加另一个StackPane。覆盖的窗格将阻止Tooltips 或在窗格未聚焦时鼠标悬停时发生的任何其他事情。您还可以最小化您的任何阶段,它们不会始终处于领先地位。

    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

      【讨论】:

        【解决方案3】:

        我想出了这个替代解决方案,因为我发现在我的案例中将 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(); 
            }    
        
        }
        

        【讨论】:

        • 这甚至保留了鼠标相关的事件,例如悬停、进入、退出。不错的解决方案!
        【解决方案4】:

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

        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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-08-07
          • 1970-01-01
          • 2017-11-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多