如何在JavaFX中创建可滚动的上下文菜单?

时间:2015-08-12 15:20:39

标签: javafx contextmenu scrollable

我的情况是上下文菜单可能会添加数百个菜单项。默认情况下,上下文菜单将在弹出窗口的顶部/底部显示滚动按钮,但它占据屏幕的整个高度。我尝试设置maxHeight和prefHeight值,但这没有效果。

理想情况下,我想在顶部和底部显示滚动条而不是滚动按钮(即将其放在滚动窗格中)。

以下是我目前拥有的代码片段:

ContextMenu menu = new ContextMenu();
menu.setMaxHeight(500);
menu.setPrefHeight(500);
for(TabFX<T> tab : overflowTabs) {
  MenuItem item = new MenuItem(tab.getTabName());
  if (tab.getGraphic() != null) item.setGraphic(tab.getGraphic());
  item.setOnAction(e -> {
    select(tab);
    layoutTabs();
  });
  menu.getItems().add(item);
}
Point2D p = overflowBtn.localToScreen(0, overflowBtn.getHeight());
menu.show(overflowBtn, p.getX(), p.getY());

有解决方法吗?

2 个答案:

答案 0 :(得分:3)

我遇到了同样的问题,我使用javafx.stage.Popup类和ScrollPane包含VBox来保存菜单项,从而解决了这个问题。

Popup popup = new Popup();
VBox vBox = new VBox();
for (int i = 0; i < 4; i++)
{
    Button item = new Button("item " + i);
    item.setOnAction(...);
    vBox.getChildren().add(item);
}
ScrollPane scrollPane = new ScrollPane(vBox);
scrollPane.setMaxHeight(500);//Adjust max height of the popup here
scrollPane.setMaxWidth(200);//Adjust max width of the popup here
popup.getContent().add(scrollPane);
popup.show(rootWindow);

注意:由于您无法将MenuItem放入VBox,因此我在示例中使用了Button,因为它具有setOnAction(...)方法。但你可以随意使用:)

答案 1 :(得分:0)

要创建可滚动的ContextMenu,您需要首先限制其高度。但是ContextMenu的最大高度设置并不限制高度,因为该实现实现了computeMaxHeight,因此其增长受到私有的ContextMenuSkin的限制。的解决方案是覆盖ContextMenu:

public class MaxSizedContextMenu extends ContextMenu {

    public MaxSizedContextMenu() {
        addEventHandler(Menu.ON_SHOWING, e -> {
            Node content = getSkin().getNode();
            if (content instanceof Region) {
                ((Region) content).setMaxHeight(getMaxHeight());
            }
        });
   }
}

JavaFX ContextMenu max size has no effect

其次,您会发现,如果向ContextMenu中添加许多项,它将忽略ancher位置(例如:entriesPopup.show(this,Side.BOTTOM,0,0))。幸运的是,可以解决此问题。您首先需要将一个项目添加到ContextMenu中,然后显示它,最后显示其余项目。这将为您提供一个可唤醒的可滚动ContextMenu。

例如:

contextMenu.getItems().add(items.get(0)));
contextMenu.show(this, Side.BOTTOM, 0, 0);
contextMenu.getItems().addAll(items.stream().skip(1).collect(Collectors.toList()));