如何控制JavaFX工具提示的延迟?

时间:2022-09-02 14:55:44

I was playing around with JavaFX Tooltip. I realized that for me personally the delay between hovering over something and the tooltip actually appearing is too long. A look in the API reveals:

我在摆弄JavaFX工具提示。我意识到,对我个人来说,停留在某件事情上和实际出现的工具提示之间的延迟太长了。从API中可以看出:

Typically, the tooltip is "activated" when the mouse moves over a Control. There is usually some delay between when the Tooltip becomes "activated" and when it is actually shown. The details (such as the amount of delay, etc) is left to the Skin implementation.

通常,当鼠标移动到控件上时,工具提示会被“激活”。当工具提示被“激活”和实际显示时之间通常会有一些延迟。细节(例如延迟的数量等)留给皮肤实现。

After some further investigation, I was not able to find any possibility to control this behavior. The JavaFX CSS Reference has no information about delay time and a runtime-evaluation of getCssMetaData() did not help either.

经过进一步的调查,我找不到任何控制这种行为的可能性。JavaFX CSS引用没有关于延迟时间的信息,对getCssMetaData()的运行时评估也没有帮助。

I know, that there is a way to control the tooltips manually via onMouseEntered and onMouseExited, but is there really no other way? Or am I missing an obvious option?

我知道,有一种方法可以通过onmouseenter和onmouseexit手动控制工具提示,但是真的没有其他方法吗?还是我错过了一个明显的选择?

7 个解决方案

#1


14  

There is an existing feature request for this: JDK-8090477 Customizable visibility timing for Tooltip.

对此有一个现有的特性请求:工具提示的可自定义可见时间。

The feature request is currently scheduled for integration into Java 9. Attached to the issue I linked is a patch you can apply to allow you to get this functionality in earlier Java versions.

该特性请求目前被安排用于集成到Java 9中。附加到我所链接的问题的是一个补丁,您可以应用它以使您能够在早期的Java版本中获得这个功能。

Your other option is just to create your own popup control using one of the techniques in:

您的另一个选择是使用以下技术之一创建您自己的弹出控件:

#2


38  

I use the next hack for this 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();
    }
}

#3


4  

I find that with the above implementation there's still a delay sometimes that I cannot explain.

我发现在上面的实现中仍然有一些延迟,我无法解释。

The following has worked for me and removed the delay entirely:

以下内容对我很有效,完全消除了延迟:

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();
      }
   });
}

#4


3  

Extends Tooltip or put on Application class. (Only java8)

扩展工具提示或放到应用程序类中。(只有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);
        }
    }

#5


2  

Indeed since JavaFX 2, the behavior of the tooltips is managed internally within the class Tooltip by the static field BEHAVIOR that cannot be modified using specific public methods so for now If you don't want to reinvent the wheel or wait for Java 9, the only way is by using the Reflection API as next:

事实上自从JavaFX 2,工具提示的行为管理内部类静态字段提示的行为不能修改使用特定公共方法所以现在如果你不想重新发明*或等待Java 9,唯一的方法是通过使用反射API为下:

/**
 * 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);
    }
}

#6


2  

Hello, I can't comment until I reach a reputation of 50 but I wanted to correct the response given by Bruno Pado. The code he posted did not work in JDK 8u121. The issue was in which declared field it accessed. The fix is simple, change the index from 1 to 0. Working code posted below:

你好,我要到50岁的时候才能发表评论,但是我想纠正布鲁诺·帕多的回答。他发布的代码在JDK 8u121中不起作用。问题是它访问的声明字段。解决方法很简单,将索引从1改为0。工作代码公布如下:

/**
 * <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);
    }
}

Hope this helps anyone who's looking to edit the tooltip delay while we wait for JFX9.

希望这能帮助任何希望在等待JFX9时编辑工具提示延迟的人。

#7


1  

In Java 9 and later, you can do

在Java 9和以后的版本中,您可以这样做

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

There is also a hideDelay property, for the delay between the tooltip appearing and it being hidden again. The default values are 1 second for the showDelay and 200 milliseconds for the hideDelay.

还有一个hideDelay属性,用于显示工具提示和再次隐藏之间的延迟。默认值为showDelay的1秒和隐藏延迟的200毫秒。

#1


14  

There is an existing feature request for this: JDK-8090477 Customizable visibility timing for Tooltip.

对此有一个现有的特性请求:工具提示的可自定义可见时间。

The feature request is currently scheduled for integration into Java 9. Attached to the issue I linked is a patch you can apply to allow you to get this functionality in earlier Java versions.

该特性请求目前被安排用于集成到Java 9中。附加到我所链接的问题的是一个补丁,您可以应用它以使您能够在早期的Java版本中获得这个功能。

Your other option is just to create your own popup control using one of the techniques in:

您的另一个选择是使用以下技术之一创建您自己的弹出控件:

#2


38  

I use the next hack for this 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();
    }
}

#3


4  

I find that with the above implementation there's still a delay sometimes that I cannot explain.

我发现在上面的实现中仍然有一些延迟,我无法解释。

The following has worked for me and removed the delay entirely:

以下内容对我很有效,完全消除了延迟:

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();
      }
   });
}

#4


3  

Extends Tooltip or put on Application class. (Only java8)

扩展工具提示或放到应用程序类中。(只有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);
        }
    }

#5


2  

Indeed since JavaFX 2, the behavior of the tooltips is managed internally within the class Tooltip by the static field BEHAVIOR that cannot be modified using specific public methods so for now If you don't want to reinvent the wheel or wait for Java 9, the only way is by using the Reflection API as next:

事实上自从JavaFX 2,工具提示的行为管理内部类静态字段提示的行为不能修改使用特定公共方法所以现在如果你不想重新发明*或等待Java 9,唯一的方法是通过使用反射API为下:

/**
 * 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);
    }
}

#6


2  

Hello, I can't comment until I reach a reputation of 50 but I wanted to correct the response given by Bruno Pado. The code he posted did not work in JDK 8u121. The issue was in which declared field it accessed. The fix is simple, change the index from 1 to 0. Working code posted below:

你好,我要到50岁的时候才能发表评论,但是我想纠正布鲁诺·帕多的回答。他发布的代码在JDK 8u121中不起作用。问题是它访问的声明字段。解决方法很简单,将索引从1改为0。工作代码公布如下:

/**
 * <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);
    }
}

Hope this helps anyone who's looking to edit the tooltip delay while we wait for JFX9.

希望这能帮助任何希望在等待JFX9时编辑工具提示延迟的人。

#7


1  

In Java 9 and later, you can do

在Java 9和以后的版本中,您可以这样做

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

There is also a hideDelay property, for the delay between the tooltip appearing and it being hidden again. The default values are 1 second for the showDelay and 200 milliseconds for the hideDelay.

还有一个hideDelay属性,用于显示工具提示和再次隐藏之间的延迟。默认值为showDelay的1秒和隐藏延迟的200毫秒。