getStyleableParent() method of Tooltip class is returning styleable parent only when BEHAVIOR class handles showing. When you use show method to manually show tooltip then BEHAVIOR.hoveredNode will be always null, and css style will be not applied to tooltip.
My proposition is to return ownerNode when BEHAVIOR.hoveredNode is null.
I created post on my blog about this bug -> http://plumblog.herokuapp.com/2014/08/27/JavaFX-tooltip-styleable-parent-bug/
Example application showing the problem:
public class Main extends Application {
public static class TooltipFix extends Tooltip {
public TooltipFix(String text) {
super(text);
}
@Override
public Styleable getStyleableParent() {
Styleable styleableParent = super.getStyleableParent();
// if default behavior is not returning styleable parent
// then return owner node
if (styleableParent != null) {
return styleableParent;
} else {
return getOwnerNode();
}
}
}
@Override
public void start(Stage primaryStage) throws Exception{
GridPane gridPane = new GridPane();
Parent root = gridPane;
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
primaryStage.getScene().getStylesheets().clear();
primaryStage.getScene().getStylesheets().add(getClass().getResource("style.css").toExternalForm());
Label lblTooltipBug = new Label("Tooltip bugged");
lblTooltipBug.getStyleClass().add("label-with-tooltip");
// original tooltip
Tooltip tooltipBug = new Tooltip("I'm broken");
lblTooltipBug.setTooltip(tooltipBug);
gridPane.add(lblTooltipBug, 0, 0);
Label lblTooltipFix = new Label("Tooltip fixed");
lblTooltipFix.getStyleClass().add("label-with-tooltip");
gridPane.add(lblTooltipFix, 0, 1);
// fixed tooltip
TooltipFix tooltipFix = new TooltipFix("I'm repaired");
lblTooltipFix.setTooltip(tooltipFix);
Button btnShowTooltip = new Button("Show tooltips");
btnShowTooltip.setOnAction(event -> {
showTooltip(lblTooltipBug);
showTooltip(lblTooltipFix);
});
gridPane.add(btnShowTooltip, 0, 2);
gridPane.setVgap(20);
gridPane.setAlignment(Pos.CENTER);
}
public static void showTooltip(Label label) {
if (label != null && label.getTooltip() != null) {
// offset
Point2D point = label.localToScene(100, 0);
label.getTooltip().setAutoHide(true);
label.getTooltip().show(label, point.getX()
+ label.getScene().getX() + label.getScene().getWindow().getX(), point.getY()
+ label.getScene().getY() + label.getScene().getWindow().getY());
}
}
public static void main(String[] args) {
launch(args);
}
}
CSS:
.label-with-tooltip .tooltip {
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);
-fx-font-weight: bold;
-fx-padding: 5;
-fx-border-width:1;
-fx-background-color: #FBEFEF;
-fx-text-fill: #cc0033;
-fx-border-color:#cc0033;
}
My proposition is to return ownerNode when BEHAVIOR.hoveredNode is null.
I created post on my blog about this bug -> http://plumblog.herokuapp.com/2014/08/27/JavaFX-tooltip-styleable-parent-bug/
Example application showing the problem:
public class Main extends Application {
public static class TooltipFix extends Tooltip {
public TooltipFix(String text) {
super(text);
}
@Override
public Styleable getStyleableParent() {
Styleable styleableParent = super.getStyleableParent();
// if default behavior is not returning styleable parent
// then return owner node
if (styleableParent != null) {
return styleableParent;
} else {
return getOwnerNode();
}
}
}
@Override
public void start(Stage primaryStage) throws Exception{
GridPane gridPane = new GridPane();
Parent root = gridPane;
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
primaryStage.getScene().getStylesheets().clear();
primaryStage.getScene().getStylesheets().add(getClass().getResource("style.css").toExternalForm());
Label lblTooltipBug = new Label("Tooltip bugged");
lblTooltipBug.getStyleClass().add("label-with-tooltip");
// original tooltip
Tooltip tooltipBug = new Tooltip("I'm broken");
lblTooltipBug.setTooltip(tooltipBug);
gridPane.add(lblTooltipBug, 0, 0);
Label lblTooltipFix = new Label("Tooltip fixed");
lblTooltipFix.getStyleClass().add("label-with-tooltip");
gridPane.add(lblTooltipFix, 0, 1);
// fixed tooltip
TooltipFix tooltipFix = new TooltipFix("I'm repaired");
lblTooltipFix.setTooltip(tooltipFix);
Button btnShowTooltip = new Button("Show tooltips");
btnShowTooltip.setOnAction(event -> {
showTooltip(lblTooltipBug);
showTooltip(lblTooltipFix);
});
gridPane.add(btnShowTooltip, 0, 2);
gridPane.setVgap(20);
gridPane.setAlignment(Pos.CENTER);
}
public static void showTooltip(Label label) {
if (label != null && label.getTooltip() != null) {
// offset
Point2D point = label.localToScene(100, 0);
label.getTooltip().setAutoHide(true);
label.getTooltip().show(label, point.getX()
+ label.getScene().getX() + label.getScene().getWindow().getX(), point.getY()
+ label.getScene().getY() + label.getScene().getWindow().getY());
}
}
public static void main(String[] args) {
launch(args);
}
}
CSS:
.label-with-tooltip .tooltip {
-fx-effect: dropshadow(three-pass-box, rgba(0,0,0,0.8), 10, 0, 0, 0);
-fx-font-weight: bold;
-fx-padding: 5;
-fx-border-width:1;
-fx-background-color: #FBEFEF;
-fx-text-fill: #cc0033;
-fx-border-color:#cc0033;
}