6

Is there a way to add a JMenuItem (or similar button-type object) to a JMenuBar?

Adding a JMenuItem doesn't play well with the layout of a JMenuBar, and buttons look too button-like.

Should we be tweaking the button to look like a JMenuItem or tweaking the JMenuBar to display the JMenuItem correctly? Or something else altogether?

thedude19
  • 2,643
  • 5
  • 34
  • 43

8 Answers8

3

The following code implements camickr's solution, although I would have come up with the same thing after seeing the default way JMenuItems are rendered in a JMenuBar. It looks reasonably authentic and responds to clicks, but not to the mnemonic.

I tried giving the JMenuItems accelerators (see code) and that works but that looks really weird.

public class TheDude19 extends JFrame {

   private class Action1 extends AbstractAction {
      private Action1() {
         super("Action1");
         putValue(MNEMONIC_KEY, (int) '1');
         // putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_MASK));
      }
      public void actionPerformed(ActionEvent arg0) {
         System.out.println("Action 1!");
      }
   }
   private class Action2 extends AbstractAction {
      private Action2() {
         super("Action2");
         putValue(MNEMONIC_KEY, (int) '2');
      }
      public void actionPerformed(ActionEvent arg0) {
         System.out.println("Action 2!");
      }
   }
   private class NarrowMenuItem extends JMenuItem {

      public NarrowMenuItem(Action a) {
         super(a);
      }
      public Dimension getMaximumSize() {
         return new Dimension(super.getPreferredSize().width, super.getMaximumSize().height);
      }
   }
   public TheDude19() {
      JMenuItem menu1 = new NarrowMenuItem(new Action1());
      JMenuItem menu2 = new NarrowMenuItem(new Action2());
      JMenuBar mb = new JMenuBar();
      mb.add(menu1);
      mb.add(menu2);
      add(mb, BorderLayout.NORTH);
      setSize(400, 300);
   }

   public static void main(String[] args) {
      (new TheDude19()).setVisible(true);
   }

}
Carl Smotricz
  • 66,391
  • 18
  • 125
  • 167
2

JMenuItem doesn't play well with the layout of a JMenuBar

A menubar use a BoxLayout which will try to strech the component to its maximum size. Try using:

menuItem.setMaximumSize( menuItem.getPreferredSize() );

If you need more help post your SSCCE showing the problem.

camickr
  • 321,443
  • 19
  • 166
  • 288
2

Just tweak the JButton.

button= new JButton("MenuItem");
button.setOpaque(true);
button.setContentAreaFilled(false);
button.setBorderPainted(false);
button.setFocusable(false);
button.addActionListener(new buttonHandler());
menuBar.add(button);

setContentAreaFilled makes it see-through,
setBorderPainted gets rid of the border,
setFocusable gets rid of the tiny border around the text.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
Praijer
  • 31
  • 3
0

Yup. Or do it the easy way

mb.add(new JMenuItem(closeAction) {
    public Dimension getMaximumSize() {
        return new Dimension(
            super.getPreferredSize().width, 
            super.getMaximumSize().height);
    }
});

It creates a class file, but meh.

PaulMurrayCbr
  • 1,167
  • 12
  • 16
0

Maybe you're forgetting your JMenu. You need to put the JMenuItem in a JMenu, then you add the JMenu to the JMenuBar.

To build a menu bar you need to do something like the following:

JMenuBar myBar = new JMenuBar();

JMenu fileMenu = new JMenu("File");

JMenuItem newFileMenuItem = new JMenuItem("New");
newFileMenuItem.addActionListener(new ActionListerner() { ... Define Action Handler here... });

fileMenu.add(newFileMenuItem);

myBar.add(fileMenu);
Daniel Bingham
  • 12,414
  • 18
  • 67
  • 93
  • No, I'm not forgetting anything. I'm well aware of the structure of JMenuBar, JMenu, JMenuItem. My question was whether there was a way to 'skip' JMenu altogether and add a JMenuItem directly to a JMenuBar. Thanks though. – thedude19 Dec 07 '09 at 20:25
  • I don't believe there is, it sounds like what you're looking for in that case is a JToolBar: http://java.sun.com/javase/6/docs/api/ and not a JMenuBar. – Daniel Bingham Dec 07 '09 at 20:49
  • Are you trying to do something like the Linux utility panels where you can have alias links along with menus? – Daniel Bingham Dec 07 '09 at 20:50
0

To get the button to look like a JMenu just add a rollover effect and remove the border of the button (See code below for example)

Required imports

import javax.swing.*;
import java.awt.event.*;
import javax.swing.event.*;
import java.awt.Dimension;
import java.awt.Color;

Code

JButton tstButton = new JButton(); //Button

tstButton.setText("Test"); //Button Text

tstButton.setOpaque(false); //These remove the button filling and border
tstButton.setContentAreaFilled(false);
tstButton.setBorder(null);
tstButton.setFocusable(false);

tstButton.setRolloverEnabled(true); //Allows the button to detect when mouse is over it
tstButton.getModel().addChangeListener(new ChangeListener()
{
    @Override
    public void stateChanged(ChangeEvent e) 
    {
        ButtonModel model = (ButtonModel) e.getSource();

        if(model.isRollover())
        {
            tstButton.setBackground(Color.RED); //Changes the colour of the button
            tstButton.setOpaque(true);
        } 

        else 
        {
            tstButton.setBackground(null);
            tstButton.setOpaque(false);
        }
     }
});

Dimension dBt = new Dimension(75,25); //Sets the size of the button in the  JMenuBar
tstButton.setMinimumSize(dBt);
tstButton.setPreferredSize(dBt);
tstButton.setMaximumSize(dBt);

tstButton.setMnemonic('T'); //Allows you to press Alt+T on your keyboard to press the button

tstButton.addActionListener(new ActionListener() //Adds action listener so it can do something
{
    public void actionPerformed(ActionEvent e) 
    {
        System.out.println("Button pressed");
    }
});

menuBar.add(tstButton); //Adds the button to the JMenuBar

Edit

There is a much improved way to do this

JButton tstButton = new JButton();
tstButton.setVisible(false);
tstButton.addActionListener(new CustomActionListener());

menuBar.add(tstButton);

JMenu menuButton = new JMenu();
addHotKey(menuButton, "shift C", 'm', "Menu Button","pressed");
menuButton.addMouseListener(new CustomMouseListener());
menuButton.addMenuKeyListener(new CustomKeyListener());

menuBar.add(menuButton);

public void addHotKey(JMenu J, String s, char c, String S, String key)
{
    Action buttonAction = new AbstractAction(S) 
    {
        @Override
        public void actionPerformed(ActionEvent evt) 
        {
            clcikComponent(tstButton);
        }
    };

    J.setAction(buttonAction);

    buttonAction.putValue(Action.MNEMONIC_KEY, KeyEvent.getExtendedKeyCodeForChar(c));

    J.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
    KeyStroke.getKeyStroke(s), key);

    J.getActionMap().put(key, buttonAction);
}

class CustomMouseListener implements MouseListener
{
    public void mouseClicked(MouseEvent e) 
    {
        clcikComponent(m_Invisible);
    }

    public void mousePressed(MouseEvent e){}

    public void mouseReleased(MouseEvent e){}

    public void mouseEntered(MouseEvent e){}

    public void mouseExited(MouseEvent e){}
}

class CustomKeyListener implements MenuKeyListener
{
    @Override
    public void menuKeyTyped(MenuKeyEvent e)
    {
        char c = e.getKeyChar();
        if(c==KeyEvent.VK_ENTER)
        {
            if(m_code.isSelected())
            {
                clcikComponent(m_Invisible);
            }
        }
    }

    @Override
    public void menuKeyPressed(MenuKeyEvent e){}

    @Override
    public void menuKeyReleased(MenuKeyEvent e){}
}

public void clcikComponent(JButton comp)
{
    comp.doClick();
}

class CustomActionListener implements ActionListener
{
    @Override
    public void actionPerformed(ActionEvent e)
    {
        //Makes Button Perform Action
    }
}
Dan
  • 7,286
  • 6
  • 49
  • 114
0

Getting the UI and the code both to look good took a while. We ended up attaching a mouse adapter to the JMenu's underlying component:

JMenu selectData = new JMenu("Select data...");

selectData.getComponent().addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        // Our code to open a window for choosing data series here...
        // [...]
    }
});

menuBar.add(selectData);

I guess we'll add a KeyAdapter as well, but haven't yet.

Florian Sesser
  • 5,972
  • 1
  • 25
  • 26
0

I had something like this happen recently I had a JMenuBar that only had 2 JMenuItems in (so note that I haven't tried this in a mixed JMenu and JMenuItem environment.

At first I ended up changing the Layout to a FlowLayout with a left alignment, but that left too much space in-between the components. I messed around with trying to do various things, but was very unsatisfied. What I ended up doing was just using a JMenu, but overriding some of it's behaviors so that it pretended to be a JMenuItem. Like so:

    JMenuBar mainMenuBar = new JMenuBar();
    final JMenu quitMenuItem = new JMenu("Quit");
    quitMenuItem.addMenuListener(new MenuListener() {
        public void menuSelected(MenuEvent e) {
            System.exit(0);

        }
        public void menuDeselected(MenuEvent e) {}
        public void menuCanceled(MenuEvent e) {}
    });

    quitMenuItem.setPopupMenuVisible(false);
    final JMenu aboutMenuItem = new JMenu("About");

    aboutMenuItem.addMenuListener(new MenuListener() {
        public void menuSelected(MenuEvent e) {
            JOptionPane.showMessageDialog(MainFrame.this, "Assignment 3 With Swing UI. Author: T.Byrne", "About", JOptionPane.INFORMATION_MESSAGE);
            aboutMenuItem.setSelected(false);//otherwise it will still be selected after the dialog box.  
        }
        public void menuDeselected(MenuEvent e) {}

        public void menuCanceled(MenuEvent e) {}
    });
    aboutMenuItem.setPopupMenuVisible(false);
    mainMenuBar.add(quitMenuItem);
    mainMenuBar.add(aboutMenuItem);
    this.setJMenuBar(mainMenuBar);
Kylar
  • 8,876
  • 8
  • 41
  • 75
  • The problem is that the menuSelected event can be fired without actually clicking on the menu. You didn't notice this because you don't have regular menus in your menu bar. If you click on a regular menu to expand its popup menu, then move over to another menu, that one will be automatically selected and it's popup expanded. If you move over your special menu, then you will exit your application just by hovering your mouse over it, without clicking it. – Andrei Vajna II Apr 23 '12 at 10:59