FilipK
FilipK

Reputation: 125

JavaFX's Tooltip showDuration doesn't work

I want to display a tooltip inside a TextField when user copies data from it to notify him that it happened and so there is my code.

public class TestController {
    @FXML private TextField textField;
    private final Clipboard clipboard;
    private ContextMenu menu;
    private MenuItem menuCopy;

    @FXML protected void initialize() {
        clipboard = Clipboard.getSystemClipboard();
        menu = new ContextMenu();

        menuCopy = new MenuItem("Copy");
        menuCopy.setOnAction(this::copy);

        textField.setContextMenu(menu);
    }

    private void copy(ActionEvent event) {
        final ClipboardContent content = new ClipboardContent();
        if(((TextField) menu.getUserData()).getSelectedText().length() == 0)
            content.putString(((TextField) menu.getUserData()).getText());
        else
            content.putString(((TextField) menu.getUserData()).getSelectedText());
        clipboard.setContent(content);

        Point2D p = ((TextField) menu.getUserData()).localToScreen(0,0);
        Tooltip test = new Tooltip("Copied");
        test.setShowDuration(new Duration(2000));
        test.show(((TextField) menu.getUserData()), p.getX(), p.getY());
    }
}

But the setShowDuration doesn't seem to work. It will be displayed forever.

Upvotes: 1

Views: 656

Answers (2)

Slaw
Slaw

Reputation: 45786

When you install a Tooltip via Tooltip#install(Node,Tooltip)1 there are three event handlers added to the given Node, all related to mouse events. It is these event handlers that implement the showDelay and showDuration functionality. This is done internally by using Timelines. However, when you manually show a Tooltip via one of its show methods you completely bypass this behavior2. In other words, your Tooltip has the same functionality as any other PopupControl.

If you want to manually display a Tooltip and have it disappear after a specified amount of time you'll have to implement that yourself. Here's a proof-of-concept:

import javafx.animation.PauseTransition;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.util.Duration;

public class NotifyingTextField extends TextField {

  private final Tooltip tooltip = new Tooltip("Copied contents to clipboard");
  private final PauseTransition hideAnimation = new PauseTransition();

  {
    hideAnimation.durationProperty().bind(tooltip.showDurationProperty());
    hideAnimation.setOnFinished(e -> tooltip.hide());
    tooltip.setShowDuration(Duration.seconds(2.0));
  }

  @Override
  public void copy() {
    var selectedText = getSelectedText();
    if (!selectedText.isEmpty()) {
      super.copy();

      var point = localToScreen(0, 0);
      tooltip.show(this, point.getX(), point.getY());
      hideAnimation.playFromStart();
    } 
  }
}

Of course, you may be able to find a third-party library that offers a ready-made solution.


1. Even setting properties such as Control#tooltip or Tab#tooltip will delegate to #install(Node,Tooltip).
2. This is true even if the Tooltip is installed. Manually calling show bypasses all the functionality added by the mouse event handlers.

Upvotes: 6

Ahmed Emad
Ahmed Emad

Reputation: 674

I think it's the way you are implementing it, I tried it and it works for me

PasswordField pf = new PasswordField();
Tooltip tooltip = new Tooltip("Your password must be\nat least 8 characters in length");
tooltip.setShowDuration(new Duration(2000));
pf.setTooltip(tooltip);

If this doesn't work with you try to help us to help you by providing snippet of your code that I can test without adding anything to it

Upvotes: 1

Related Questions