带有ToolTip的JavaFX菜单(不是MenuItem)?

时间:2018-07-25 15:36:22

标签: javafx javafx-8

是否有可能将工具提示添加到JavaFX(Sub-)菜单?

MenuItems的通常(但很丑陋-为什么菜单不能仅由节点组成?!)解决方案是使用CustomMenuItem并在其中放置标签(即Node)-可以分配标签工具提示。

但是如何为(子)菜单实现此目的?请参见以下示例:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.stage.Stage;

public class CustomSubMenu extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        MenuButton menuButton = new MenuButton("Menu");

        Label helloLabel = new Label("Hello...");
        helloLabel.tooltipProperty().setValue(new Tooltip("World!"));
        menuButton.getItems().add(new CustomMenuItem(helloLabel));


        Menu submenu = new Menu("This Submenu needs a ToolTip!");
        //             new CustomMenuItem(new Menu()); // doesn't work, because Menu is not a Node.
        submenu.getItems().add(new MenuItem("Some other Item"));
        menuButton.getItems().add(submenu);

        primaryStage.setScene(new Scene(menuButton));
        primaryStage.show();

    }

}

2 个答案:

答案 0 :(得分:1)

每个menuItem(当然还有一个菜单)都与一个节点关联。该项目至少显示一次后,即可访问该节点。然后可以通过item.getStyleableNode()访问该节点(因为fx9,关于fx8,请参见下文),并且可以在该节点上设置工具提示。

因此,基本上,方法是监听该瞬间,然后安装工具提示。下面的示例通过

  • 为菜单/项目创建工具提示,并将其放入其属性
  • 在父菜单上注册一个onShown处理程序,并安装工具提示(如果可用)

基本片段:

String tooltipKey = "TOOL_TIP";
MenuItem normalItem = new MenuItem("Good .. ");
normalItem.getProperties().put(tooltipKey, new Tooltip("Morning!"));
menuButton.getItems().add(normalItem);
Menu submenu = new Menu("This Submenu needs a ToolTip!");
submenu.getProperties().put(tooltipKey, new Tooltip("It's meee!"));
menuButton.setOnShown(e -> {
    menuButton.getItems().forEach(item -> {
        Node node = item.getStyleableNode();
        if (node != null && item.getProperties().get(tooltipKey) instanceof Tooltip) {
            Tooltip tip = (Tooltip) item.getProperties().get(tooltipKey);
            Tooltip.install(node, tip);
        }
    });

});

对于fx8,基本方法是相同的-但是访问表示menuItem的节点是令人讨厌的(请注意:请勿在生产中!*咳嗽..):

  • getStyleableNode是fx9的新功能,因此我们不得不使用内部api和实现细节进行修改
  • 很难找到节点可用的时间:明显的钩子将是menuButton上SHOWN的eventHandler,但似乎不受支持(似乎不受支持-并没有)尽力而为)
  • 一种解决方法是,先聆听showingProperty,获取contextMenu,听其skinProperty,然后在设置好外观后进行安装

代码段:

// not working - what's wrong?
menuButton.addEventHandler(MenuButton.ON_SHOWN, e -> {
    LOG.info("not getting here?");
    // install tooltips here
});

ChangeListener<Skin> skinListener = (src, ov, skin) -> {
    ContextMenuContent content = (ContextMenuContent) skin.getNode();
    VBox menuBox = (VBox) content.getChildrenUnmodifiable().get(0);
    menuBox.getChildren().forEach(node -> {
        // implementation detail: the menuItem is set in the node's properties
        if (node.getProperties().get(MenuItem.class) instanceof MenuItem) {
            MenuItem item = (MenuItem) node.getProperties().get(MenuItem.class);
            if (node != null && item.getProperties().get(tooltipKey) instanceof Tooltip) {
                Tooltip tip = (Tooltip) item.getProperties().get(tooltipKey);
                Tooltip.install(node, tip);
            }

        }

    });
};
menuButton.showingProperty().addListener((src, ov, nv) -> {
    ContextMenu popup = submenu.getParentPopup();
    if (popup != null) {
        if (popup.getSkin() == null) {
            popup.skinProperty().addListener(skinListener);
        } else {
            popup.skinProperty().removeListener(skinListener);
        }
    }
});

答案 1 :(得分:0)

我想出了一种简单的方法来欺骗 MenuItem 作为控件 Label 节点,并使用如下代码:

    Label lb=new Label("MenuItem Text");
    lb.setStyle("-fx-text-fill:black;");
    MenuItem myMenuItem = new MenuItem(null, lb);
    Tooltip tips = new Tooltip("Your tip text here");   
    Tooltip.install(myMenuItem.getGraphic(), tips);

将工具提示设置为标签,这对我来说很好。