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.

Cajunluke
  • 3,103
  • 28
  • 28
Kien Truong
  • 11,179
  • 2
  • 30
  • 36

7 Answers7

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);
    }
}
Steve McLeod
  • 51,737
  • 47
  • 128
  • 184
  • 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? – Adam Goode Nov 07 '09 at 15:08
  • 2
    I also did something slightly differently: popup.show(c, 0, c.getHeight()); – Adam Goode Nov 07 '09 at 15:09
  • 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. – Kien Truong Nov 07 '09 at 16:15
  • 1
    As far I know, there is no dropdown JButton. You have to craft your own, perhaps by adding an appropriate icon to the JButton. – Steve McLeod Nov 08 '09 at 10:11
  • What if you want to make this so that it has the arrow (down) image that you see in Microsoft. – Doug Hauf Feb 24 '14 at 14:02
  • Could you add a screenshot, please? – Anders Lindén May 29 '16 at 08:49
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().

Steve McLeod
  • 51,737
  • 47
  • 128
  • 184
Kenneth Evans
  • 2,179
  • 19
  • 26
  • 2
    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 up – Steve McLeod Dec 19 '12 at 12:56
  • 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. – Kenneth Evans Dec 20 '12 at 19:11
  • This is a far better answer and should get more votes. Looks better than having the mouse click location. – Raj Aug 17 '13 at 08:26
  • 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())`. – Nand Aug 18 '20 at 16:31
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) {}
        });
    }
}
luca
  • 7,178
  • 7
  • 41
  • 55
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.

Cristina
  • 1,991
  • 3
  • 17
  • 24
2

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

TH.
  • 1,738
  • 1
  • 12
  • 15
  • just that this is the more specific link: http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html#popup – pratikabu Jun 07 '13 at 15:15
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

jitter
  • 53,475
  • 11
  • 111
  • 124
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);
Zweibieren
  • 387
  • 3
  • 12