5

I have a situation where a context menu can potentially have hundreds of menu items added to it. By default a context menu will show scroll buttons at the top/bottom of the popup, but it takes the full height of the screen. I tried setting the maxHeight and prefHeight values, but this had no effect.

Ideally I would like to show a scroll bar instead of scroll buttons at the top and bottom (ie put it in a scroll pane).

Here is a snippet of the code that I am currently have:

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

Is there a workaround for this?

user3461443
  • 191
  • 1
  • 1
  • 5

2 Answers2

3

I had the same issue and I solved it by using the javafx.stage.Popup class with a ScrollPane whichs contains a VBox and that holds the menu items.

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

Note: As you can not put a MenuItem into a VBox, I have used a Button in the example because it has the setOnAction(...) method. But you can use whatever you like :)

sonallux
  • 83
  • 5
0

To create a scrollable ContextMenu you need to first limit its height. But the max height setting of the ContextMenu does not limit the height, since the implements computeMaxHeight and therefore its growth is limited by ContextMenuSkin which is private. A solution for the is to override 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)

Second you will find, that if you add to many items to the ContextMenu, it will ignore the ancher position (e.g.: entriesPopup.show(this, Side.BOTTOM, 0, 0)). Luckily it is possible to work around this problem. You first need to add one of the items to the ContextMenu then show it and finally at the rest. This will give you a wokring scrollable ContextMenu.

E.g.:

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