JMenuBar с выпадающим списком для скрытого JMenu

Хотите создать JMenuBar. Если окно-JFrame.width слишком маленькое, чтобы отображать все JMenu из JMenuBar, в JMenuBar появляется кнопка, и все скрытые JMenu можно выбрать в раскрывающемся списке. Как я могу понять это, пожалуйста?


person user781640    schedule 23.07.2013    source источник


Ответы (3)


Я бы посмотрел JToolBar, проиллюстрированный здесь. Вы можете использовать любой необходимый макет, и большинство L&F позволяют панели становиться плавающим окном.

person trashgod    schedule 23.07.2013

Используйте CardLayout, чтобы иметь панель, содержащую как обычное меню, так и меню, реализованное с помощью кнопки. Затем добавьте к нему ComponentListener (ComponentAdapter) и выберите нужную реализацию меню в методе слушателя componentResized().

В коде это будет выглядеть примерно так:

JMenuBar createCustomMenu() {
    final CardLayout layout = new CardLayout();
    final JMenuBar menu = new JMenuBar();
    menu.setLayout(layout);

    // Here you should create the normal, wide menu
    JComponent normalMenu = createNormalMenu();
    // Here you create the compressed, one button version
    JComponent compressedMenu = createCompressedMenu();

    menu.add(normalMenu, "normal");
    menu.add(compressedMenu, "compressed");

    menu.addComponentListener(new ComponentAdapter() {
        public void componentResized(ComponentEvent e) {
            if (menu.getPreferredSize().getWidth() > menu.getWidth()) {
                layout.show(menu, "compressed");
            } else {
                layout.show(menu, "normal");
            }
        }
    });

    return menu;
}

(редактировать: изменено, чтобы вернуть JMenuBar, так как это работает нормально)

person kiheru    schedule 23.07.2013

Вот какой-то старый код, с которым я играл 5 лет назад. Это было так давно, что я даже не помню, насколько хорошо работает код. Он был разработан для JToolBar, но может дать вам некоторые идеи о том, как это сделать с JMenuBar:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
/**
*
* @author subanark
*/
public class PopupMenuLayout implements java.awt.LayoutManager
{
    private JPopupMenu popupMenu = new JPopupMenu();
    private JButton popupButton = new JButton(new PopupAction());

    /** Creates a new instance of PopupMenuLayout */
    public PopupMenuLayout()
    {
    }

    /** If the layout manager uses a per-component string,
    * adds the component <code>comp</code> to the layout,
    * associating it
    * with the string specified by <code>name</code>.
    *
    * @param name the string to be associated with the component
    * @param comp the component to be added
    */
    public void addLayoutComponent(String name, Component comp)
    {
    }

    /**
    * Lays out the specified container.
    * @param parent the container to be laid out
    */
    public void layoutContainer(Container parent)
    {
        //  Position all buttons in the container

        Insets insets = parent.getInsets();
        int x = insets.left;
        int y = insets.top;
        System.out.println("bottom: " + insets.bottom);
        int spaceUsed = insets.right + insets.left;

        for (int i = 0; i < parent.getComponentCount(); i++ )
        {
            Component aComponent = parent.getComponent(i);
            aComponent.setSize(aComponent.getPreferredSize());
            aComponent.setLocation(x,y);
            int componentWidth = aComponent.getPreferredSize().width;
            x += componentWidth;
            spaceUsed += componentWidth;
        }

        //  All the buttons won't fit, add extender button
        //  Note: the size of the extender button changes once it is added
        //  to the container. Add it here so correct width is used.

        int parentWidth = parent.getSize().width;

        if (spaceUsed > parentWidth)
        {
            popupMenu.removeAll();
            parent.add(popupButton);
            popupButton.setSize( popupButton.getPreferredSize() );
            int popupX = parentWidth - insets.right - popupButton.getSize().width;
            popupButton.setLocation(popupX, y );
            spaceUsed += popupButton.getSize().width;
        }

        //  Remove buttons that don't fit and add to the popup menu

//      System.out.println(spaceUsed + " ::: " + parentWidth);

        int lastVisibleButtonIndex = 1;

        while (spaceUsed > parentWidth)
        {
            lastVisibleButtonIndex++;
            int last = parent.getComponentCount() - lastVisibleButtonIndex;

            Component component = parent.getComponent( last );
            component.setVisible( false );
            spaceUsed -= component.getSize().width;

            addComponentToPopup(component);

//          popupButton.setLocation( button.getLocation() );
//          System.out.println(spaceUsed + "  :  " + parentWidth);
        }

    }

    private void addComponentToPopup(Component component)
    {
        System.out.println(component.getClass());

        if (component instanceof JButton)
        {
            JButton button = (JButton)component;
            JMenuItem menuItem = new JMenuItem(button.getText());
            menuItem.setIcon( button.getIcon() );

            ActionListener[] listeners = button.getActionListeners();

            for (int i = 0; i < listeners.length; i++)
                menuItem.addActionListener( listeners[i] );

            popupMenu.insert(menuItem, 0);
        }

        if (component instanceof JToolBar.Separator)
        {
            popupMenu.insert( new JSeparator(), 0);
        }
    }

    /**
    * Calculates the minimum size dimensions for the specified
    * container, given the components it contains.
    * @param parent the component to be laid out
    * @see #preferredLayoutSize
    */
    public Dimension minimumLayoutSize(Container parent)
    {
        return popupButton.getMinimumSize();
    }

    /** Calculates the preferred size dimensions for the specified
    * container, given the components it contains.
    * @param parent the container to be laid out
    *
    * @see #minimumLayoutSize
    */
    public Dimension preferredLayoutSize(Container parent)
    {
        //  Move all components to the container and remove the extender button

        parent.remove(popupButton);
/*
        while ( popupMenu.getComponentCount() > 0 )
        {
            Component aComponent = popupMenu.getComponent(0);
            popupMenu.remove(aComponent);
            parent.add(aComponent);
        }
*/
        //  Calculate the width of all components in the container

        Dimension d = new Dimension();
        d.width += parent.getInsets().right + parent.getInsets().left;

        for (int i = 0; i < parent.getComponents().length; i++)
        {
            Component component = parent.getComponent(i);
            component.setVisible( true );
            d.width += component.getPreferredSize().width;
            d.height = Math.max(d.height, component.getPreferredSize().height);
        }

//      d.height += parent.getInsets().top + parent.getInsets().bottom + 5;
        d.height += parent.getInsets().top + parent.getInsets().bottom;
        return d;
    }

    /** Removes the specified component from the layout.
    * @param comp the component to be removed
    */
    public void removeLayoutComponent(Component comp)
    {
    }

    protected class PopupAction extends AbstractAction
    {
        public PopupAction()
        {
            super(">>");
        }

        public void actionPerformed(ActionEvent e)
        {
            JComponent component = (JComponent)e.getSource();
            popupMenu.show(component,0,component.getHeight());
        }
    }

    public static void main(String[] argv)
    {
        ActionListener simpleAction = new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                System.out.println(e.getActionCommand());
            }
        };

        JToolBar toolBar = new JToolBar();
        toolBar.setLayout(new PopupMenuLayout());
        toolBar.add( createButton("one", simpleAction) );
        toolBar.add( createButton("two", simpleAction) );
        toolBar.add( createButton("three", simpleAction) );
        toolBar.add( createButton("four", simpleAction) );
        toolBar.add( createButton("five", simpleAction) );
        toolBar.add( createButton("six", simpleAction) );
        toolBar.addSeparator();
        toolBar.add( createButton("seven", simpleAction) );
        toolBar.add( createButton("eight", simpleAction) );
        toolBar.addSeparator();
        toolBar.add( createButton("nine", simpleAction) );
        toolBar.add( createButton("ten", simpleAction) );

        JFrame f = new JFrame();
        f.getContentPane().setLayout(new BorderLayout());
        f.getContentPane().add(toolBar,BorderLayout.NORTH);
        f.setBounds(300,200,400,300);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setVisible(true);
    }

    private static JButton createButton(String text, ActionListener listener)
    {
        JButton button = new JButton(text);
        button.addActionListener( listener );
        return button;
    }
}

В этом случае кнопка панели инструментов была преобразована в JMenu, когда не было свободного места. В вашем случае у вас уже есть JMenu, поэтому вы должны иметь возможность просто переместить JMenu из JMenuBar во всплывающее меню. Однако вам нужно будет изменить код, чтобы всегда перемещать меню из всплывающего меню обратно в строку меню, прежде чем определять предпочтительный размер строки меню.

person camickr    schedule 23.07.2013