У меня такое же решение, как предложено @Slaw.Моя идея состоит в том, чтобы сделать его более централизованным, чтобы вы могли передавать свой узел и его регионы, в которых вы хотите показать всплывающие подсказки.
В приведенной ниже демонстрации вы можете использовать setToolTips () как метод статической точности для нескольких узлов..
Примечание: некоторая часть логики упоминается из реализации ядра Tooltip;)
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
import java.util.HashMap;
import java.util.Map;
public class MultiTooltipDemo extends Application {
private double lastMouseX;
private double lastMouseY;
private static int TOOLTIP_XOFFSET = 10;
private static int TOOLTIP_YOFFSET = 7;
@Override
public void start(Stage stage) throws Exception {
StackPane root = new StackPane();
Scene sc = new Scene(root, 600, 600);
stage.setScene(sc);
stage.show();
StackPane box1 = new StackPane();
box1.setMaxSize(200, 200);
box1.setStyle("-fx-background-color:red, blue, yellow, green; -fx-background-insets: 0 100 100 0, 0 0 100 100, 100 100 0 0, 100 0 0 100;");
root.getChildren().add(box1);
Map<String, Rectangle2D> tooltips = new HashMap<>();
tooltips.put("I am red", new Rectangle2D(0, 0, 100, 100));
tooltips.put("I am blue", new Rectangle2D(100, 0, 100, 100));
tooltips.put("I am yellow", new Rectangle2D(0, 100, 100, 100));
tooltips.put("I am green", new Rectangle2D(100, 100, 100, 100));
setToolTips(box1, tooltips);
}
private void setToolTips(Node node, Map<String, Rectangle2D> tooltips) {
Duration openDelay = Duration.millis(1000);
Duration hideDelay = Duration.millis(5000);
Tooltip toolTip = new Tooltip();
Timeline hideTimer = new Timeline();
hideTimer.getKeyFrames().add(new KeyFrame(hideDelay));
hideTimer.setOnFinished(event -> {
toolTip.hide();
});
Timeline activationTimer = new Timeline();
activationTimer.getKeyFrames().add(new KeyFrame(openDelay));
activationTimer.setOnFinished(event -> {
Bounds nodeScreenBounds = node.localToScreen(node.getBoundsInLocal());
double nMx = nodeScreenBounds.getMinX();
double nMy = nodeScreenBounds.getMinY();
toolTip.setText("");
tooltips.forEach((str, bounds) -> {
double mnX = nMx + bounds.getMinX();
double mnY = nMy + bounds.getMinY();
double mxX = mnX + bounds.getWidth();
double mxY = mnY + bounds.getHeight();
if (lastMouseX >= mnX && lastMouseX <= mxX && lastMouseY >= mnY && lastMouseY <= mxY) {
toolTip.setText(str);
}
});
if (!toolTip.getText().isEmpty()) {
toolTip.show(node.getScene().getWindow(), lastMouseX + TOOLTIP_XOFFSET, lastMouseY + TOOLTIP_YOFFSET);
hideTimer.playFromStart();
}
});
node.setOnMouseMoved(e -> {
double buffPx = 2;
double eX = e.getScreenX();
double eY = e.getScreenY();
// Not hiding for slight mouse movements while tooltip is showing
if (hideTimer.getStatus() == Animation.Status.RUNNING) {
if (lastMouseX - buffPx <= eX && lastMouseX + buffPx >= eX && lastMouseY - buffPx <= eY && lastMouseY + buffPx >= eY) {
return;
}
}
lastMouseX = e.getScreenX();
lastMouseY = e.getScreenY();
toolTip.hide();
hideTimer.stop();
activationTimer.playFromStart();
});
node.setOnMouseExited(e -> {
toolTip.hide();
activationTimer.stop();
hideTimer.stop();
});
}
public static void main(String[] args) {
Application.launch(args);
}
}