How to create a JButton with a menu?
Asked Answered
Y

7

37

I want to create a Toolbar in my application. If you click a button on that toolbar, it will pop up a menu, just like in Eclipse's toolbar. I don't know how to do this in Swing. Can someone help me please? I've tried Google but found nothing.

Yet answered 7/11, 2009 at 10:47 Comment(0)
F
34

This is way harder in Swing than it needs to be. So instead of pointing you to tutorials I've created a fully working example.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class ToolbarDemo {

    public static void main(String[] args) {
        final JFrame frame = new JFrame();
        frame.setPreferredSize(new Dimension(600, 400));
        final JToolBar toolBar = new JToolBar();

        //Create the popup menu.
        final JPopupMenu popup = new JPopupMenu();
        popup.add(new JMenuItem(new AbstractAction("Option 1") {
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(frame, "Option 1 selected");
            }
        }));
        popup.add(new JMenuItem(new AbstractAction("Option 2") {
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(frame, "Option 2 selected");
            }
        }));

        final JButton button = new JButton("Options");
        button.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                popup.show(e.getComponent(), e.getX(), e.getY());
            }
        });
        toolBar.add(button);

        frame.getContentPane().add(toolBar, BorderLayout.NORTH);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}
Folberth answered 7/11, 2009 at 15:2 Comment(6)
I have been doing something like this, but without the JToolBar. Does your solution have the behavior where if you click the button again with the menu up, it pops up the menu again, instead of dismissing it?Cobos
I also did something slightly differently: popup.show(c, 0, c.getHeight());Cobos
Thank you. This is the easiest to understand solution that I've found, so I'll use it although it's not exactly a Dropdown JButton.The other solutions are too complicated for me to understand. I've list some of them below. <netbeans.dzone.com/news/drop-down-buttons-swing-new-al pushing-pixels.org/?p=199Yet
As far I know, there is no dropdown JButton. You have to craft your own, perhaps by adding an appropriate icon to the JButton.Folberth
What if you want to make this so that it has the arrow (down) image that you see in Microsoft.Kristeenkristel
Could you add a screenshot, please?Cochard
C
17

I don't see why this is harder than it needs to be or why you should use a MouseListener. The solution by Steve McLeod works, but where the menu appears depends on where the mouse was clicked. Why not just use an ActionListener as normally used for a JButton. It seems neither harder nor less hard.

final JPopupMenu menu = new JPopupMenu();
menu.add(...whatever...);

final JButton button = new JButton();
button.setText("My Menu");
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent ev) {
        menu.show(button, button.getBounds().x, button.getBounds().y
           + button.getBounds().height);
    }
});

This positions the menu about the same as a menu in a JMenuBar for me, and the position is consistent. You could place it differently by modifying the x and y in menu.show().

Crackup answered 16/10, 2012 at 18:16 Comment(4)
The problem with approach is that the popup menu only appears when the user releases the mouse button. The menu should appear upon mouse down, not mouse upFolberth
You're right. I didn't notice. I still like it better than the other way, but neither is completely satisfactory. I ended up not implementing what I was trying to do that way and so didn't use it anyway. I guess you could do what you did and use my version of menu.show with the button coordinates to avoid the position inconsistency.Crackup
This is a far better answer and should get more votes. Looks better than having the mouse click location.Endless
This is wrong. The positions are relative to component you pass in menu.show, to get the desired effect you would need menu.show(button, 0, button.getHeight()).Wardmote
Z
3

Here is a simple and nice class

enter image description here

import javax.swing.JPopupMenu;
import javax.swing.JToggleButton;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class MenuButton extends JToggleButton {

    JPopupMenu popup;

    public MenuButton(String name, JPopupMenu menu) {
        super(name);
        this.popup = menu;
        addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ev) {
                JToggleButton b = MenuButton.this;
                if (b.isSelected()) {
                    popup.show(b, 0, b.getBounds().height);
                } else {
                    popup.setVisible(false);
                }
            }
        });
        popup.addPopupMenuListener(new PopupMenuListener() {
            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                MenuButton.this.setSelected(false);
            }
            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {}
        });
    }
}
Zelma answered 28/4, 2015 at 8:19 Comment(0)
J
2

I think it's the same as in AWT.

You should put an ActionCommand on that button and when it's executed show the pop-up menu according to the mouse coordinates.

Justness answered 7/11, 2009 at 10:50 Comment(1)
As mentioned in another answer, it would bring up the popup menu on mouseReleased, not on mouseDownOverlarge
T
2

See the section Bringing Up a Popup Menu, in How to Use Menus.

Taxicab answered 7/11, 2009 at 11:35 Comment(1)
just that this is the more specific link: docs.oracle.com/javase/tutorial/uiswing/components/…Arbogast
S
1

I'm not sure I understand you correctly but if you want to know how to make toolbars in Swing check this

Java Tutorials: How to Use Tool Bars and this

Java Tutorials: How to Use Actions

Sternlight answered 7/11, 2009 at 11:30 Comment(0)
S
0

Above, Adam Goode asked,

Does your solution have the behavior where if you click the button again with the menu up, it pops up the menu again, instead of dismissing it?

This turned out to be a testing task. I finally solved it with an invokeLater to re-vanish the popup in that particular case. My solution also allows the client to tailor the button and the popup menu.

    /**
 * A button that will popup a menu.
 * The button itself is a JLabel and can be adjusted with all
 * label attributes. The popup menu is returned by getPopup;
 * menu items must be added to it.
 * <p>
 * Clicks outside the menu will dismiss it.
*/
public class MenuButton extends JLabel 
        implements MouseListener, PopupMenuListener {
    JPopupMenu popMenu;

    @SuppressWarnings("")
    public MenuButton() {
        super();
        popMenu = new JPopupMenu();
        addMouseListener(this);
        popMenu.addPopupMenuListener(this);
    }

    public JPopupMenu getPopup() { return popMenu; }
    
    @Override
    public void mousePressed(MouseEvent e) {
        if ( ! popMenu.isShowing()) {
            popMenu.show(this, 0, getBounds().height);
        }
    }
    @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { 
        SwingUtilities.invokeLater(()->{
            if (popMenu.isShowing()) {
                //  if shpwing, it was hidden and reshown
                //  by a mouse down in the 'this' button
                popMenu.setVisible(false);
            }
        });
    }

    @Override public void mouseClicked(MouseEvent e) { }
    @Override public void mouseReleased(MouseEvent e) { }
    @Override public void mouseEntered(MouseEvent e) { }
    @Override public void mouseExited(MouseEvent e) { }
    @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
    @Override public void popupMenuCanceled(PopupMenuEvent e) { }

} // end MenuButton

Sample invocation

    MenuButton button = new MenuButton();
    JPopupMenu menu = button.getPopup();
    menu.add("Browse Sample");
    menu.add("Save As ...");
    Icon hamburger = IOUtils.loadIconResource(
            IndexGofer.class, "images/hamburgerMenu.png");
            (IOUtils is on page http://physpics.com/Java/tools/
                  You should use your own tool to load an icon.)
    button.setIcon(hamburger);
    button.setOpaque(false);
Snoddy answered 5/3, 2022 at 1:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.