web-dev-qa-db-fra.com

Comment contrôler le délai de JavaFX Tooltip?

Je jouais avec JavaFX Tooltip . J'ai réalisé que pour moi personnellement, le délai entre le survol de quelque chose et l'infobulle s'affichant trop longtemps est trop long. Un coup d'oeil dans l'API révèle:

En règle générale, l'info-bulle est "activée" lorsque la souris survole un contrôle. Il y a généralement un certain délai entre le moment où l'info-bulle devient "activée" et le moment où elle est affichée. Les détails (tels que le délai, etc.) sont laissés à l’implémentation de la peau.

Après une enquête plus approfondie, je n’ai pas trouvé de possibilité de contrôler ce comportement. Le Référence CSS JavaFX ne contient aucune information sur le délai et une évaluation de getCssMetaData() à l'exécution ne l'a pas aidé non plus.

Je sais qu'il existe un moyen de contrôler les info-bulles manuellement via onMouseEntered et onMouseExited, mais n'y a-t-il vraiment pas d'autre moyen? Ou est-ce que je manque une option évidente?

28
Turing85

Il existe déjà une demande de fonctionnalité pour cela: JDK-8090477 Synchronisation de visibilité personnalisable pour Tooltip

L'intégration de Java 9 à la demande de fonctionnalité est actuellement prévue. Un correctif que vous pouvez appliquer pour vous permettre d'obtenir cette fonctionnalité dans les versions antérieures de Java est associé au problème que j'ai lié.

Votre autre option consiste simplement à créer votre propre contrôle contextuel à l’aide d’une des techniques suivantes:

16
jewelsea

J'utilise le prochain hack pour cela via Reflection

public static void hackTooltipStartTiming(Tooltip tooltip) {
    try {
        Field fieldBehavior = tooltip.getClass().getDeclaredField("BEHAVIOR");
        fieldBehavior.setAccessible(true);
        Object objBehavior = fieldBehavior.get(tooltip);

        Field fieldTimer = objBehavior.getClass().getDeclaredField("activationTimer");
        fieldTimer.setAccessible(true);
        Timeline objTimer = (Timeline) fieldTimer.get(objBehavior);

        objTimer.getKeyFrames().clear();
        objTimer.getKeyFrames().add(new KeyFrame(new Duration(250)));
    } catch (Exception e) {
        e.printStackTrace();
    }
}
40
Igor Luzhanov

Je trouve qu'avec la mise en œuvre ci-dessus, il y a encore parfois un retard que je ne peux pas expliquer.

Ce qui suit a fonctionné pour moi et a totalement supprimé le retard:

public static void bindTooltip(final Node node, final Tooltip tooltip){
   node.setOnMouseMoved(new EventHandler<MouseEvent>(){
      @Override  
      public void handle(MouseEvent event) {
         // +15 moves the tooltip 15 pixels below the mouse cursor;
         // if you don't change the y coordinate of the tooltip, you
         // will see constant screen flicker
         tooltip.show(node, event.getScreenX(), event.getScreenY() + 15);
      }
   });  
   node.setOnMouseExited(new EventHandler<MouseEvent>(){
      @Override
      public void handle(MouseEvent event){
         tooltip.hide();
      }
   });
}
6
Aleks Messier

En Java 9 et ultérieur, vous pouvez faire

Tooltip tooltip = new Tooltip("A tooltip");
tooltip.setShowDelay(Duration.seconds(3));

Il existe également une propriété hideDelay, pour le délai entre l'affichage de l'info-bulle et son masquage à nouveau. Les valeurs par défaut sont 1 seconde pour la showDelay et 200 millisecondes pour la hideDelay.

4
James_D

Bonjour, je ne peux pas commenter avant d'avoir atteint une réputation de 50 mais je voulais corriger la réponse donnée par Bruno Pado. Le code qu'il a posté ne fonctionnait pas dans JDK 8u121. Le problème était dans quel champ déclaré il accédait. Le correctif est simple, changez l'index de 1 à 0. Code de travail publié ci-dessous:

/**
 * <p>
 * Hack TooltipBehavior 
 */
static {
    try {
        Tooltip obj = new Tooltip();
        Class<?> clazz = obj.getClass().getDeclaredClasses()[0];
        Constructor<?> constructor = clazz.getDeclaredConstructor(
                Duration.class,
                Duration.class,
                Duration.class,
                boolean.class);
        constructor.setAccessible(true);
        Object tooltipBehavior = constructor.newInstance(
                new Duration(250),  //open
                new Duration(5000), //visible
                new Duration(200),  //close
                false);
        Field fieldBehavior = obj.getClass().getDeclaredField("BEHAVIOR");
        fieldBehavior.setAccessible(true);
        fieldBehavior.set(obj, tooltipBehavior);
    }
    catch (Exception e) {
        Logger.error(e);
    }
}

J'espère que cela aidera tous ceux qui cherchent à éditer le délai d'infobulle en attendant JFX9.

3
d_scalzi

Étend l'info-bulle ou la classe d'application. (Uniquement Java8)

    /**
     * <p>
     * Hack TooltipBehavior 
     */
    static {
        try {
            Tooltip obj = new Tooltip();
            Class<?> clazz = obj.getClass().getDeclaredClasses()[1];
            Constructor<?> constructor = clazz.getDeclaredConstructor(
                    Duration.class,
                    Duration.class,
                    Duration.class,
                    boolean.class);
            constructor.setAccessible(true);
            Object tooltipBehavior = constructor.newInstance(
                    new Duration(250),  //open
                    new Duration(5000), //visible
                    new Duration(200),  //close
                    false);
            Field fieldBehavior = obj.getClass().getDeclaredField("BEHAVIOR");
            fieldBehavior.setAccessible(true);
            fieldBehavior.set(obj, tooltipBehavior);
        }
        catch (Exception e) {
            Logger.error(e);
        }
    }
3
Bruno Prado

En effet depuis JavaFX 2, le comportement des info-bulles est géré en interne au sein de la classe Tooltip par le champ statique BEHAVIOR qui ne peut pas être modifié à l'aide de méthodes publiques spécifiques. Le seul moyen est d’utiliser l’API Reflection API comme suivant:

/**
 * Hack allowing to modify the default behavior of the tooltips.
 * @param openDelay The open delay, knowing that by default it is set to 1000.
 * @param visibleDuration The visible duration, knowing that by default it is set to 5000.
 * @param closeDelay The close delay, knowing that by default it is set to 200.
 * @param hideOnExit Indicates whether the tooltip should be hide on exit, 
 * knowing that by default it is set to false.
 */
private static void updateTooltipBehavior(double openDelay, double visibleDuration,
    double closeDelay, boolean hideOnExit) {
    try {
        // Get the non public field "BEHAVIOR"
        Field fieldBehavior = Tooltip.class.getDeclaredField("BEHAVIOR");
        // Make the field accessible to be able to get and set its value
        fieldBehavior.setAccessible(true);
        // Get the value of the static field
        Object objBehavior = fieldBehavior.get(null);
        // Get the constructor of the private static inner class TooltipBehavior
        Constructor<?> constructor = objBehavior.getClass().getDeclaredConstructor(
            Duration.class, Duration.class, Duration.class, boolean.class
        );
        // Make the constructor accessible to be able to invoke it
        constructor.setAccessible(true);
        // Create a new instance of the private static inner class TooltipBehavior
        Object tooltipBehavior = constructor.newInstance(
            new Duration(openDelay), new Duration(visibleDuration),
            new Duration(closeDelay), hideOnExit
        );
        // Set the new instance of TooltipBehavior
        fieldBehavior.set(null, tooltipBehavior);
    } catch (Exception e) {
        throw new IllegalStateException(e);
    }
}
2
Nicolas Filotto

En JavaFx 9, le délai d'infobulle peut être défini via CSS. Cela semble pervers, de faire cela dans une feuille de style, mais c'est probablement ce qu'ils veulent dire quand ils disent "Les détails (tels que le délai, etc.) sont laissés à l'implémentation de Skin.".

https://docs.Oracle.com/javase/9/docs/api/javafx/scene/doc-files/cssref.html#tooltip

Donc, vous pouvez faire quelque chose comme ça:

.tooltip {
    -fx-show-delay: 250ms;
}
0
Franz Deschler