Adding a clickable, action-firing JMenuItem directly to a JMenuBar?
Asked Answered
P

8

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?

Porras answered 7/12, 2009 at 20:2 Comment(0)
R
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);
   }

}
Ryon answered 7/12, 2009 at 21:0 Comment(0)
A
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.

Award answered 7/12, 2009 at 20:7 Comment(1)
Didn't work for me, some white space to the left (where JMenuItems reserve space for icons) remained.Eldrid
A
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.

Anabaptist answered 4/3, 2015 at 19:46 Comment(0)
L
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);
Lotson answered 7/12, 2009 at 20:9 Comment(3)
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.Porras
I don't believe there is, it sounds like what you're looking for in that case is a JToolBar: java.sun.com/javase/6/docs/api and not a JMenuBar.Lotson
Are you trying to do something like the Linux utility panels where you can have alias links along with menus?Lotson
B
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);
Burdett answered 1/3, 2012 at 14:32 Comment(1)
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.Conjunct
S
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.

Sisak answered 18/5, 2012 at 4:37 Comment(0)
S
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
    }
}
Styracaceous answered 2/6, 2015 at 19:21 Comment(0)
E
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.

Eldrid answered 5/9, 2019 at 16:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.