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