带工具提示的JavaFX菜单(不是MenuItem)?
是否有可能向JavaFX(子)菜单添加工具提示 菜单项的常见解决方案(但很难看——为什么菜单不能不仅仅由节点组成?!)是使用CustomMenuItem并在其中放置标签(即节点)——标签可以指定工具提示 但是我如何才能为(子)菜单实现这一点呢?请参见以下示例:带工具提示的JavaFX菜单(不是MenuItem)?,javafx,javafx-8,Javafx,Javafx 8,是否有可能向JavaFX(子)菜单添加工具提示 菜单项的常见解决方案(但很难看——为什么菜单不能不仅仅由节点组成?!)是使用CustomMenuItem并在其中放置标签(即节点)——标签可以指定工具提示 但是我如何才能为(子)菜单实现这一点呢?请参见以下示例: import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.stage.St
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();
}
}
每个菜单项(当然也是一个菜单)都与一个节点相关联。在项目至少显示一次后,可以访问该节点。然后可以通过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的节点是令人讨厌的(注意:不要在生产中!*cough..):
- getStyleableNode是fx9的新成员,因此我们必须使用内部api和实现细节进行破解
- 节点可用的时间更难找到:显而易见的钩子是菜单按钮上显示的事件处理程序,但似乎不受支持(似乎还不受支持-但没有挖掘)
- 一种方法是先听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);
}
}
});
//不工作-怎么了?
menuButton.addEventHandler(显示menuButton.ON,e->{
LOG.info(“不到这里?”);
//在此处安装工具提示
});
ChangeListener skinListener=(src、ov、skin)->{
ContextMenuContent content=(ContextMenuContent)skin.getNode();
VBox menuBox=(VBox)content.getChildrenUnmodifiable().get(0);
menuBox.getChildren().forEach(节点->{
//实现细节:menuItem在节点的属性中设置
if(node.getProperties().get(MenuItem.class)instanceof MenuItem){
MenuItem项=(MenuItem)node.getProperties().get(MenuItem.class);
if(node!=null&&item.getProperties().get(tooltipKey)instanceof Tooltip){
工具提示提示=(工具提示)item.getProperties().get(工具提示键);
工具提示。安装(节点、提示);
}
}
});
};
menuButton.showingProperty().addListener((src,ov,nv)->{
ContextMenu popup=子菜单.getParentPopup();
如果(弹出!=null){
if(popup.getSkin()==null){
popup.skinProperty().addListener(skinListener);
}否则{
popup.skinProperty().RemovelListener(skinListener);
}
}
});
我想出了一个简单的方法来欺骗菜单项作为控件标签节点,使用如下代码:
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);
将工具提示设置为标签,这对我来说非常有用。谢谢你,克利奥帕特拉!但似乎getStyleableNode是用Java9添加的——不幸的是,我现在只能用Java8了……对于菜单,同样的技巧也可以用。i、 e.使用菜单mu=新菜单(空,新标签(“菜单名”))。