JavaFX How Can I Center a Tooltip on a Node?

50
January 12, 2019, at 3:20 PM

I'm currently working on a form that features validation upon changing focus from one node to another and wish to display a tooltip centered above a node containing an error if one exists. I'm using the tooltip's show(Node ownerNode, double anchorX, double anchorY) method signature to specify which node I would like to attach it to and where to position it.

I've tried the following code:

Tooltip tooltip = new Tooltip("Error"); 
tooltip.show(node, 0, 0);
double tooltipMiddle = tooltip.getWidth() / 2;
tooltip.hide(); 
double nodeMiddle = node.getWidth() / 2; 
//Gets the node's x and y position within the window
Bounds bounds = node.localToScene(node.getBoundsInLocal());  
//Tooltip's bottom-right corner is set to the anchor points, so I set x to
//the node's x coordinate plus half the width of the node plus half the width
//of the tooltip 
tooltip.show(node,
             bounds.getMinX() + nodeMiddle + tooltipMiddle, bounds.getMinY());

This has gotten me very close to the center, but it's still off. I've been all over the internet trying to find help, but I'm just not finding any, so I figured I'd ask here.
Any chance I could get some insight into why I'm not able to get this working how I'd like it?

Answer 1

First you should use Bounds bounds = node.localToScreen(node.getBoundsInLocal()); as it might not be clear what the relevant Scene is.

Then calling tooltip.show(node, bounds.getMinX(), bounds.getMinY()); should give you a tooltip with an upper left corner identical to the upper upper left corner of node.

Now, tooltip.show(node, bounds.getMinX() + nodeMiddle - tooltipMiddle, bounds.getMinY() - tooltipHeight); should produce the desired result and it does for

double tooltipMiddle = (tooltip.getWidth()-18) / 2;
double tooltipHeight = tooltip.getHeight()-18;
double nodeMiddle = getWidth() / 2;

The 18 came from a little experimenting and I'm not sure why the width and height are off by that amount, but it seems to be indpendent of the length or number of lines of the text in the tooltip.

Answer 2

Code which I bring provides correct positioning of tooltip but is far from being perfect. It would take a lot of work to bring comprehensive solution (if you want we can discuss it). Going to the bottom I think you have a math problem and Tooltip class may not be the best option.

import javafx.application.Application;
import javafx.geometry.Bounds;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class TooltipApp extends Application {
    public static void main(String[] args) {
        launch(args);
    }
    @Override
    public void start(Stage stage) throws Exception {
        TextField textField = new TextField();
        textField.setPrefWidth(100.);
        Button button = new Button("Tooltip");
        HBox hBox = new HBox(textField, button);
        hBox.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE);
        Label label = new Label("Empty!");
        label.setVisible(false);
        Pane tooltipPane = new Pane(label);
        tooltipPane.setMouseTransparent(true);
        StackPane stackPane = new StackPane(hBox, tooltipPane);
        stackPane.setPrefSize(600., 400.);
        Scene scene = new Scene(stackPane);
        stage.setScene(scene);
        stage.show();
        button.setOnMouseClicked(event -> {
            if (label.isVisible()) {
                label.setVisible(false);
            } else {
                Bounds sceneBounds = textField.localToScene(textField.getBoundsInLocal());
                label.setLayoutX((sceneBounds.getMinX() + (sceneBounds.getWidth() / 2)) - (label.getWidth() / 2));
                label.setLayoutY(sceneBounds.getMinY() - label.getHeight());
                label.setVisible(true);
            }
        });
    }
}
READ ALSO
How to modify objects in a List<? extends MyObject> while iterating?

How to modify objects in a List<? extends MyObject> while iterating?

I am trying to modify a field in select objects in a List but I am unable to find a way to do so, using plain Iterator because it has no set() method

33
Java Spring-boot: Problem to finde resources

Java Spring-boot: Problem to finde resources

I have a Spring-boot backend Angular front end applicationThe application runs well if it is run on port 4200 (Running frontend from the front end)

25
Override Dashboard in TYPO3

Override Dashboard in TYPO3

Im trying to override the help_AboutmodulesAboutmodulesiframe in TYPO3I think that is the initial page when you are log in as backend user

25
Visual form builder Is this plugin compatible with Amazon S3/Cloudfront?

Visual form builder Is this plugin compatible with Amazon S3/Cloudfront?

I am using vusual form builder for one of my WordPress siteVisual form builder this plugin compatible with Amazon S3/Cloudfront? The upload function is storing the files on our S3 server correctly but the link to the file in the "Entries" section is pointing...

26