La adición de desplazamiento vertical para un JPopupMenu?

Me gustaría añadir una forma de desplazarse por los elementos de menú en un JPopupMenu, tanto como el desplazamiento a través de una lista de elementos en un JComboBox.

Digamos que tengo 10 elementos de menú. Me gustaría mostrar sólo los 5 elementos de menú en un momento, y me gustaría utilizar una barra de desplazamiento vertical botón en la parte inferior o superior de la JPopupMenu para mostrar los elementos de menú que no están en la lista y ocultar las que acabo de ver.

Es posible? Estoy usando JIDE del Software JideSplitButton, que muestra una JPopupMenu cuando se hace clic. Estoy tratando de mantener la apariencia de la barra de comandos en la que me colocaron el JideSplitButton, así que no quiero reemplazarlo con un JComboBox a menos que realmente tenga que hacerlo.

7 Kommentare

  1. 25

    Aquí es una versión que he creado utilizando una barra de desplazamiento. Se trata de un simple ejemplo, para introducir los cambios:

    import java.awt.Component;
    import java.awt.Container;
    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Insets;
    import java.awt.LayoutManager;
    import java.awt.event.AdjustmentEvent;
    import java.awt.event.AdjustmentListener;
    import java.awt.event.MouseWheelEvent;
    import java.awt.event.MouseWheelListener;
    import javax.swing.JPopupMenu;
    import javax.swing.JScrollBar;
    
    public class JScrollPopupMenu extends JPopupMenu {
        protected int maximumVisibleRows = 10;
    
        public JScrollPopupMenu() {
            this(null);
        }
    
    
        public JScrollPopupMenu(String label) {
            super(label);
            setLayout(new ScrollPopupMenuLayout());
    
            super.add(getScrollBar());
            addMouseWheelListener(new MouseWheelListener() {
                @Override public void mouseWheelMoved(MouseWheelEvent event) {
                    JScrollBar scrollBar = getScrollBar();
                    int amount = (event.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL)
                                 ? event.getUnitsToScroll() * scrollBar.getUnitIncrement()
                                 : (event.getWheelRotation() < 0 ? -1 : 1) * scrollBar.getBlockIncrement();
    
                    scrollBar.setValue(scrollBar.getValue() + amount);
                    event.consume();
                }
            });
        }
    
        private JScrollBar popupScrollBar;
        protected JScrollBar getScrollBar() {
            if(popupScrollBar == null) {
                popupScrollBar = new JScrollBar(JScrollBar.VERTICAL);
                popupScrollBar.addAdjustmentListener(new AdjustmentListener() {
                    @Override public void adjustmentValueChanged(AdjustmentEvent e) {
                        doLayout();
                        repaint();
                    }
                });
    
                popupScrollBar.setVisible(false);
            }
    
            return popupScrollBar;
        }
    
        public int getMaximumVisibleRows() {
            return maximumVisibleRows;
        }
    
        public void setMaximumVisibleRows(int maximumVisibleRows) {
            this.maximumVisibleRows = maximumVisibleRows;
        }
    
        public void paintChildren(Graphics g){
            Insets insets = getInsets();
            g.clipRect(insets.left, insets.top, getWidth(), getHeight() - insets.top - insets.bottom);
            super.paintChildren(g);
        }
    
        protected void addImpl(Component comp, Object constraints, int index) {
            super.addImpl(comp, constraints, index);
    
            if(maximumVisibleRows < getComponentCount()-1) {
                getScrollBar().setVisible(true);
            }
        }
    
        public void remove(int index) {
            //can't remove the scrollbar
            ++index;
    
            super.remove(index);
    
            if(maximumVisibleRows >= getComponentCount()-1) {
                getScrollBar().setVisible(false);
            }
        }
    
        public void show(Component invoker, int x, int y){
            JScrollBar scrollBar = getScrollBar();
            if(scrollBar.isVisible()){
                int extent = 0;
                int max = 0;
                int i = 0;
                int unit = -1;
                int width = 0;
                for(Component comp : getComponents()) {
                    if(!(comp instanceof JScrollBar)) {
                        Dimension preferredSize = comp.getPreferredSize();
                        width = Math.max(width, preferredSize.width);
                        if(unit < 0){
                            unit = preferredSize.height;
                        }
                        if(i++ < maximumVisibleRows) {
                            extent += preferredSize.height;
                        }
                        max += preferredSize.height;
                    }
                }
    
                Insets insets = getInsets();
                int widthMargin = insets.left + insets.right;
                int heightMargin = insets.top + insets.bottom;
                scrollBar.setUnitIncrement(unit);
                scrollBar.setBlockIncrement(extent);
                scrollBar.setValues(0, heightMargin + extent, 0, heightMargin + max);
    
                width += scrollBar.getPreferredSize().width + widthMargin;
                int height = heightMargin + extent;
    
                setPopupSize(new Dimension(width, height));
            }
    
            super.show(invoker, x, y);
        }
    
        protected static class ScrollPopupMenuLayout implements LayoutManager{
            @Override public void addLayoutComponent(String name, Component comp) {}
            @Override public void removeLayoutComponent(Component comp) {}
    
            @Override public Dimension preferredLayoutSize(Container parent) {
                int visibleAmount = Integer.MAX_VALUE;
                Dimension dim = new Dimension();
                for(Component comp :parent.getComponents()){
                    if(comp.isVisible()) {
                        if(comp instanceof JScrollBar){
                            JScrollBar scrollBar = (JScrollBar) comp;
                            visibleAmount = scrollBar.getVisibleAmount();
                        }
                        else {
                            Dimension pref = comp.getPreferredSize();
                            dim.width = Math.max(dim.width, pref.width);
                            dim.height += pref.height;
                        }
                    }
                }
    
                Insets insets = parent.getInsets();
                dim.height = Math.min(dim.height + insets.top + insets.bottom, visibleAmount);
    
                return dim;
            }
    
            @Override public Dimension minimumLayoutSize(Container parent) {
                int visibleAmount = Integer.MAX_VALUE;
                Dimension dim = new Dimension();
                for(Component comp : parent.getComponents()) {
                    if(comp.isVisible()){
                        if(comp instanceof JScrollBar) {
                            JScrollBar scrollBar = (JScrollBar) comp;
                            visibleAmount = scrollBar.getVisibleAmount();
                        }
                        else {
                            Dimension min = comp.getMinimumSize();
                            dim.width = Math.max(dim.width, min.width);
                            dim.height += min.height;
                        }
                    }
                }
    
                Insets insets = parent.getInsets();
                dim.height = Math.min(dim.height + insets.top + insets.bottom, visibleAmount);
    
                return dim;
            }
    
            @Override public void layoutContainer(Container parent) {
                Insets insets = parent.getInsets();
    
                int width = parent.getWidth() - insets.left - insets.right;
                int height = parent.getHeight() - insets.top - insets.bottom;
    
                int x = insets.left;
                int y = insets.top;
                int position = 0;
    
                for(Component comp : parent.getComponents()) {
                    if((comp instanceof JScrollBar) && comp.isVisible()) {
                        JScrollBar scrollBar = (JScrollBar) comp;
                        Dimension dim = scrollBar.getPreferredSize();
                        scrollBar.setBounds(x + width-dim.width, y, dim.width, height);
                        width -= dim.width;
                        position = scrollBar.getValue();
                    }
                }
    
                y -= position;
                for(Component comp : parent.getComponents()) {
                    if(!(comp instanceof JScrollBar) && comp.isVisible()) {
                        Dimension pref = comp.getPreferredSize();
                        comp.setBounds(x, y, width, pref.height);
                        y += pref.height;
                    }
                }
            }
        }
    }
    • no debería usted también reimplementar otros métodos que se basan en los índices de los componentes? Como insert(Component component, int index) y insert(Action a, int index)?
    • Sí, usted debe. Yo sólo quería crear un simple, pero totalmente funcional ejemplo. La integridad, estoy seguro de que hay más de lo que debe ser hecho.
  2. 13

    Además de la JScrollPopupMenu de arriba, yo también necesitaba un una barra de desplazamiento en un sub-menú (también conocido como un «Tirón Menú de la Derecha.») Este parece ser un caso más común. Así que me he adaptado un JMenu el uso de la JScrollPopupMenu llamado 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);
            }
        }
    }
    • Esta es una buena solución 🙂 … estoy tratando de averiguar cómo forzar el desplazamiento a un elemento específico en el sub menú utilizando esta solución, como el uso de ensureIndexIsVisible(índice) en un JList ?
    • public void ensureIndexIsVisible(int index) { Rectangle rect = getMenuComponent(index).getBounds(); ((JScrollPopupMenu)popupMenu).getScrollBar().scrollRectToVisible(rect); }
  3. 3

    Básicamente, usted puede agregar cualquier JComponents a la JPopupMenu, usted puede agregar JScrollpane para la JPopup por la anidación de JPanel /JList con otro JComponents,

    Aviso pero no es la regla que el swing GUI no permitir que dos ligero ventana emergente en el mismo tiempo, el mejor ejemplo es Error común en Swing acerca de Jtree en el JPopup

    usted tiene mirada en JWindow, crea una vez que el tiempo y re_use que para otra Acción, nada mejor alrededor para comprobar cómo emergente JWindow realmente funciona para JCalendar por Kai Toedter

  4. 0

    Como necesitaba menú con Barra de desplazamiento, acabo de reutilizar el menú emergente de Jtree.
    El truco es poner Jtree en un JViewport, de modo que sólo el botón de flecha era visible. Usted puede hacer que sea sólo un píxel pequeño o incluso menor, y el uso de eventos de JideSplitButton para abrir la ventana emergente.

    Usted puede encontrar el código en github.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea