I would like to add a way to scroll through menu items in a JPopupMenu
, much like scrolling through a list of items in a JComboBox
.
Let\'s
Here's another one I found very useful: https://tips4java.wordpress.com/2009/02/01/menu-scroller/
It can be called on JMenu or JPopupMenu like this:
MenuScroller.setScrollerFor(menuInstance, 8, 125, 3, 1);
As I needed popup menu with Scrollbar, I just reused popup menu from JComboBox. The trick was to put JComboBox in a JViewport, so that only arrow button was visible. You may make it just one pixel small or even lesser and use event from JideSplitButton to open popup.
You may find code on github.
In addition to the JScrollPopupMenu above, I also needed a a scroll bar in a sub menu (aka a "Pull Right Menu.") This seems to be a more common case. So I adapted a JMenu to use the JScrollPopupMenu called JScrollMenu:
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.MenuElement;
import javax.swing.UIManager;
import javax.swing.plaf.MenuItemUI;
import javax.swing.plaf.PopupMenuUI;
import java.awt.Component;
import java.awt.ComponentOrientation;
public class JScrollMenu extends JMenu {
// Covers the one in the JMenu because the method that creates it in JMenu is private
/** The popup menu portion of the menu.*/
private JPopupMenu popupMenu;
/**
* Constructs a new <code>JMenu</code> with no text.
*/
public JScrollMenu() {
this("");
}
/**
* Constructs a new <code>JMenu</code> with the supplied string as its text.
*
* @param s the text for the menu label
*/
public JScrollMenu(String s) {
super(s);
}
/**
* Constructs a menu whose properties are taken from the <code>Action</code> supplied.
*
* @param a an <code>Action</code>
*/
public JScrollMenu(Action a) {
this();
setAction(a);
}
/**
* Lazily creates the popup menu. This method will create the popup using the <code>JScrollPopupMenu</code> class.
*/
protected void ensurePopupMenuCreated() {
if(popupMenu == null) {
this.popupMenu = new JScrollPopupMenu();
popupMenu.setInvoker(this);
popupListener = createWinListener(popupMenu);
}
}
//////////////////////////////
//// All of these methods are necessary because ensurePopupMenuCreated() is private in JMenu
//////////////////////////////
@Override
public void updateUI() {
setUI((MenuItemUI) UIManager.getUI(this));
if(popupMenu != null) {
popupMenu.setUI((PopupMenuUI) UIManager.getUI(popupMenu));
}
}
@Override
public boolean isPopupMenuVisible() {
ensurePopupMenuCreated();
return popupMenu.isVisible();
}
@Override
public void setMenuLocation(int x, int y) {
super.setMenuLocation(x, y);
if(popupMenu != null) {
popupMenu.setLocation(x, y);
}
}
@Override
public JMenuItem add(JMenuItem menuItem) {
ensurePopupMenuCreated();
return popupMenu.add(menuItem);
}
@Override
public Component add(Component c) {
ensurePopupMenuCreated();
popupMenu.add(c);
return c;
}
@Override
public Component add(Component c, int index) {
ensurePopupMenuCreated();
popupMenu.add(c, index);
return c;
}
@Override
public void addSeparator() {
ensurePopupMenuCreated();
popupMenu.addSeparator();
}
@Override
public void insert(String s, int pos) {
if(pos < 0) {
throw new IllegalArgumentException("index less than zero.");
}
ensurePopupMenuCreated();
popupMenu.insert(new JMenuItem(s), pos);
}
@Override
public JMenuItem insert(JMenuItem mi, int pos) {
if(pos < 0) {
throw new IllegalArgumentException("index less than zero.");
}
ensurePopupMenuCreated();
popupMenu.insert(mi, pos);
return mi;
}
@Override
public JMenuItem insert(Action a, int pos) {
if(pos < 0) {
throw new IllegalArgumentException("index less than zero.");
}
ensurePopupMenuCreated();
JMenuItem mi = new JMenuItem(a);
mi.setHorizontalTextPosition(JButton.TRAILING);
mi.setVerticalTextPosition(JButton.CENTER);
popupMenu.insert(mi, pos);
return mi;
}
@Override
public void insertSeparator(int index) {
if(index < 0) {
throw new IllegalArgumentException("index less than zero.");
}
ensurePopupMenuCreated();
popupMenu.insert(new JPopupMenu.Separator(), index);
}
@Override
public void remove(JMenuItem item) {
if(popupMenu != null){
popupMenu.remove(item);
}
}
@Override
public void remove(int pos) {
if(pos < 0) {
throw new IllegalArgumentException("index less than zero.");
}
if(pos > getItemCount()) {
throw new IllegalArgumentException("index greater than the number of items.");
}
if(popupMenu != null){
popupMenu.remove(pos);
}
}
@Override
public void remove(Component c) {
if(popupMenu != null){
popupMenu.remove(c);
}
}
@Override
public void removeAll() {
if(popupMenu != null){
popupMenu.removeAll();
}
}
@Override
public int getMenuComponentCount() {
return (popupMenu == null) ? 0 : popupMenu.getComponentCount();
}
@Override
public Component getMenuComponent(int n) {
return (popupMenu == null) ? null : popupMenu.getComponent(n);
}
@Override
public Component[] getMenuComponents() {
return (popupMenu == null) ? new Component[0] : popupMenu.getComponents();
}
@Override
public JPopupMenu getPopupMenu() {
ensurePopupMenuCreated();
return popupMenu;
}
@Override
public MenuElement[] getSubElements() {
return popupMenu == null ? new MenuElement[0] : new MenuElement[]{popupMenu};
}
@Override
public void applyComponentOrientation(ComponentOrientation o) {
super.applyComponentOrientation(o);
if(popupMenu != null) {
int ncomponents = getMenuComponentCount();
for(int i = 0; i < ncomponents; ++i) {
getMenuComponent(i).applyComponentOrientation(o);
}
popupMenu.setComponentOrientation(o);
}
}
@Override
public void setComponentOrientation(ComponentOrientation o) {
super.setComponentOrientation(o);
if(popupMenu != null) {
popupMenu.setComponentOrientation(o);
}
}
}
Basically you can add any JComponents to the JPopupMenu, you can add JScrollpane to the JPopup by nesting JPanel / JList with another JComponents,
Notice but there is rule that swing GUI doesn't allowing two lightweight popup window in same time, best example is common Bug in Swing about JComboBox in the JPopup
you have look at JWindow, create once time and re_use that for another Action, nothing best around as to check how popup JWindow really works for JCalendar by Kai Toedter
Alternately you may want to consider JidePopupMenu: Scrollable JPopupMenu
May be this http://www.javabeginner.com/java-swing/java-scrollable-popup-menu