Search code examples
javatooltipjavafx-8

Tooltip: how to get mouse coordinates that triggered the tip?


The requirement: show the coordinates of the mouseEvent that triggered the tooltip as its text. For a contextMenu, the location is stored in the contextMenuEvent, so I would listen to contextMenuRequested and update as needed.

Couldn't find anything similar for a tooltip, so played a bit (see example below):

  • at the time of showing/shown, I could query the tooltip location: for AnchorLocation.CONTENT_TOP_LEFT its x/y seems to be about the last mouse location, though slightly increased. Could be accidental, though, is unspecified (and as such unusable) and definitely off for other anchor types

  • the brute force method would be to install a mouse-moved handler and store the current mouse location into the tooltip's properties. Wouldn't like to, because that's duplicating functionality, as ToolTipBehaviour already keeps track of the triggering location, unfortunately top secretly, as usual

  • extending tooltip wouldn't help as well, due to the private scope of the behaviour

Any ideas?

public class DynamicTooltipMouseLocation extends Application {

    protected Button createButton(AnchorLocation location) {
        Tooltip t = new Tooltip("");
        String text = location != null ? location.toString() 
                : t.getAnchorLocation().toString() + " (default)";
        if (location != null) {
            t.setAnchorLocation(location);
        }
        t.setOnShown(e -> {
            // here we get a stable tooltip
            t.textProperty().set("x/y: " + t.getX() + "/" + t.getY() + "\n" +
                    "ax/y: " + t.getAnchorX() + "/" + t.getAnchorY());
        });
        Button button = new Button(text);
        button.setTooltip(t);
        button.setOnContextMenuRequested(e -> {
            LOG.info("context: " + text + "\n      " +
                    "scene/screen/source " + e.getSceneX() + " / " + e.getScreenX() + " / " + e.getX());
        });
        button.setOnMouseMoved(e -> {
            LOG.info("moved: " + text + "\n      " +
            "scene/screen/source " + e.getSceneX() + " / " + e.getScreenX() + " / " + e.getX());
        });
        return button;
    }

    @Override
    public void start(Stage stage) throws Exception {
        VBox pane = new VBox(createButton(AnchorLocation.CONTENT_TOP_LEFT));
        Scene scene = new Scene(pane);
        stage.setScene(scene);
        stage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }

    @SuppressWarnings("unused")
    private static final Logger LOG = Logger
            .getLogger(DynamicTooltipMouseLocation.class.getName());
}

Solution

  • I'm not sure if I've understood your question right, but if you are looking for the screen coordinates of the mouse, right at the position when the tooltip is shown, I think you almost got them.

    You have already looked at Tooltip class and its inner class TooltipBehavior.

    For starters there are these hardcoded offsets:

    private static int TOOLTIP_XOFFSET = 10;
    private static int TOOLTIP_YOFFSET = 7;
    

    Then, in the inner class a mouse moved handler is added to the node, tracking the mouse in screen coordinates, and showing the tooltip based on several timers:

        t.show(owner, event.getScreenX()+TOOLTIP_XOFFSET,
                                event.getScreenY()+TOOLTIP_YOFFSET);
    

    Given that it uses this show method:

    public void show(Window ownerWindow, double anchorX, double anchorY)
    

    The coordinates you are looking for are just these:

    coordMouseX=t.getAnchorX()-TOOLTIP_XOFFSET;
    coordMouseY=t.getAnchorY()-TOOLTIP_YOFFSET;
    

    no matter how the tooltip anchor location is set.

    I've checked this also in your answer to the question, and these values are the same as the Point2D screen you set to the tooltip.

    Anyway, since this solution uses hardcoded fields from private API, I assume you won't like it, since those can change without notice...