ContextMenu keeps an up and down arrows as a special type of MenuItem called ArrowMenuItem. The structure goes like this:
ContextMenu > ContextMenuSkin > ContextMenuContent > ArrowMenuItem
ArrowMenuItem is a non-static package-private class. ContextMenuContent has two instances of this class: upArrow and downArrow and these two instances are shown only when the items can't fit in the ContextMenu. ContextMenuContent uses a Timeline to scroll the ContextMenu, so when an ENTERED type MouseEvent is fired on any of those arrow items, the Timeline starts scrolling the content up or down based on hovered ArrowMenuItem. The Timeline stops when the mouse exits that region.
ContextMenuContent has a method scroll that is all you need, but unfortunately, this method is not public.
Possible solutions:
Extend ContextMenuSkin, ContextMenuContent to expose the method scroll. In this way, you can call lookup ContextMenuContent from the skin and use that method to scroll all the way up or down.
Use menu-up-arrow and menu-down-arrow style classes to lookup the arrow nodes. Once you get the arrow node, you can stimulate a mouse ENTERED event to make the ContextMenu scroll up or down. Note that in this way the user has to wait until the scrolling finishes since the Timeline has a fixed scrolling rate. Then you need to consume this event after the scrolling is over.
Sample code:
ContextMenuSkin skin = (ContextMenuSkin) contextMenu.getSkin();
Node up = skin.getNode().lookup(".menu-up-arrow");
Node down = skin.getNode().lookup(".menu-down-arrow");
MouseEvent enteredEvent = new MouseEvent(MouseEvent.MOUSE_ENTERED, ...); // the remaining parameters
if (shouldScrollUp) {
up.fireEvent(enteredEvent);
} else {
down.fireEvent(enteredEvent);
}
// consume the event after scroll is over
- Using Reflection:
private static void scrollContextMenuUp(ContextMenu contextMenu) {
try {
ContextMenuSkin skin = (ContextMenuSkin) contextMenu.getSkin();
ContextMenuContent content = (ContextMenuContent) skin.getNode();
Method method = content.getClass().getDeclaredMethod("scroll", double.class);
method.setAccessible(true);
method.invoke(content, 12.0); // change this double value to scroll more
} catch (Exception e) {
System.err.println("Unable to scroll due to: " + e.getMessage());
}
}