I am trying to work around this bug in the 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(); } }
If the button on the primary stage is hovered, it will come in front of the second stage. I found that calling initOwner()
on a Stage will eliminate this behavior.
Now my problem is following: I have multiple "popups" that have a common owner (the primary stage). Hovering over controls on the primary stage doesn't cause any unexpected behavior after the initOwner()
workaround. If you however hover over controls in a popup while another popup was in focus, the hovered popup will steal focus.
Is there a way I can work around this bug for not only the primary stage but also the popups?
UPDATE: turns out my workaround has undesired side-effects. Javadocs for Stage state following:
A stage will always be on top of its parent window.
So additionally, what would be a workaround that makes the popup not "always on top" and minimizable?
3 Answers
Answers 1
There is a way to get around it by overlaying StackPanes. Create your Scene
with a StackPane
so that you can add another StackPane
when the stage has lost its focus. The overlayed pane will prevent Tooltip
s or anything else happening on mouse-over while the pane is not in focus. You may also minimize any of your stages and they won't be always-on-top.
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); } } }); } }
Answers 2
You can try this:
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()); } }
I didn't try it though, but if it works, this should be a good alternative. There is no need to restructure your layout, and you can leave all your layout in FXML, without specifying fx:id
for the tooltips.
Answers 3
You could try to unset the tooltip whenever the node's window loses focus. Such as below:
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); } }
Of course, you would have to call installTooltip
after the node is added to the component.
0 comments:
Post a Comment