如何控制JavaFX Tooltip的延迟?

问题描述 投票:0回答:9

我正在玩 JavaFX 的

Tooltip
。我意识到对我个人来说,将鼠标悬停在某物上和工具提示实际出现之间的延迟太长。查看 API 可以发现:

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

经过进一步调查,我无法找到任何控制延迟的可能性。 JavaFX CSS Reference 没有有关延迟时间的信息,并且

getCssMetaData()
的运行时评估也没有帮助。

我知道有一种方法可以通过

onMouseEntered(...)
onMouseExited(...)
手动控制工具提示,但是真的没有其他方法吗?或者我错过了一个明显的解决方案?

java css javafx-8 fxml
9个回答
51
投票

我通过反射使用下一个技巧

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

24
投票

在 Java 9 及更高版本中,你可以这样做

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

还有一个

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


16
投票

有一个现有的功能请求:JDK-8090477 可自定义工具提示的可见性计时

该功能请求当前计划集成到 Java 9 中。我链接的问题附带了一个补丁,您可以应用该补丁来允许您在早期 Java 版本中获得此功能。

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


9
投票

我发现通过上述实现,有时仍然会出现我无法解释的延迟。

以下方法对我有用并完全消除了延迟:

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
投票

在 JavaFx 9 中,可以通过 CSS 设置工具提示延迟。在样式表中执行此操作听起来很变态,但这可能就是他们所说的“细节(例如延迟量等)留给皮肤实现。”的意思。

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

所以你可以这样做:

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

5
投票

扩展工具提示或放在应用程序类上。 (仅限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
投票

事实上,从 JavaFX 2 开始,工具提示的行为是在类

Tooltip
内部通过静态字段
BEHAVIOR
进行管理的,无法使用特定的公共方法进行修改,所以现在如果您不想重新发明轮子或等待对于 Java 9,唯一的方法是使用 Reflection 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);
    }
}

3
投票

您好,在我的声誉达到 50 之前我无法发表评论,但我想纠正 Bruno Pado 给出的响应。 他发布的代码在 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);
    }
}

希望这对那些希望在等待 JFX9 期间编辑工具提示延迟的人有所帮助。


0
投票

也可以通过 SceneBuilder 22.0.0 通过向工具提示节点添加样式“-fx-show-delay”并将其设置为“100ms”来完成。这对我有用。

© www.soinside.com 2019 - 2024. All rights reserved.