3

I am having some problems regarding to the JMenuBar and I cant seem to figure it out.

I will start with an abriviation of the problem: The program consists of a JFrame, a JDialog and a JMenuBar. Initially, you will get to see a JFrame with the JMenuBar in the top. But at some point, the JDialog will pop up where a user can fill in some text fields. The problem that I'm having is that as soon as the focus goes to the JDialog, the JMenuBar disappears. What I want is that the JMenuBar stays in the top of the screen all the time, except if the whole program is NOT in focus. Here are 2 screenshots, in the first screen shot, the JFrame is selected and in the other one the JDialog is selected.

enter image description here

enter image description here

So what i actually want is instead of only seeing the JMenuBar when the focus is on the JFrame, i want to see the JMenuBar all the time. Since a JDialogs can not have the JMenuBar in the top, like a JFrame has, i decided not to have multiple JMenuBars, but just the one that should be visible all the time.

At last i will give a part of the code that is as small as possible (and still working) and also contains the problem:

import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;

/**
 * @author Guus Leijsten
 * @created Oct 27, 2012
 */
public class MenuBarProblem extends JFrame {
    public MenuBarProblem() {
        super("Frame");
        this.setMinimumSize(new Dimension(270, 200));
        this.setPreferredSize(new Dimension(800, 530));
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        JRootPane root = this.getRootPane();
    //Menu
        JMenu fileMenu = new JMenu("File");
        JMenuItem file_exit = new JMenuItem("Exit");
        file_exit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        file_exit.setToolTipText("Exit application");
        file_exit.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        fileMenu.add(file_exit);

        JMenuBar menu = new JMenuBar();
        menu.add(fileMenu);
        root.setJMenuBar(menu);

        this.setVisible(true);

        JDialog d = new JDialog(this, "Dialog");
        d.setSize(200, 100);
        d.setLocation(0, (int)root.getContentPane().getLocationOnScreen().getY());
        d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        d.setVisible(true);
    }

    public static void main(String[] args) {
        String os = System.getProperty("os.name").toLowerCase();
        if(os.indexOf("mac") >= 0) {
            System.setProperty("apple.laf.useScreenMenuBar", "true");
        }
        new MenuBarProblem();
    }
}

If I can be honoust, i think that the problem lies in the part of JRootPane. But we'll see ;)

Did anyone else encountered this problem and managed to solve it alrady, or is there anybody that wants to give it a shot?

Thanks in advance!


Added content:

In the following example I will show a version that gives some functionality to the play.

This is the program i'm making: enter image description here The second image shows the state in which the right menu is undocked. enter image description here Obviously the JMenuBar should still be visible and operational because without it, a lot of functionalities of the program will be disabled.

At this point i'm starting to think that it is impossible for the JMenuBar to stay visible when the dialog (undocked menu) is undocked, and focussed on.

I know that the JMenuBar on a JDialog can not be in the mac osx style (top of screen), so are there any other techniques i can use for undocking, which does give me a mac osx style JMenuBar?

Triplle
  • 99
  • 1
  • 6
  • not osx user, whats happend by using JMenuBar correctly, put that to the JFrame – mKorbel Oct 27 '12 at 07:53
  • What do you mean mKorbel? I'm going to need a little more than this. Like what is the correct way of using JMenuBar? and put what to the JFrame? @mKorbel – Triplle Oct 27 '12 at 09:58
  • [for example](http://docs.oracle.com/javase/tutorial/uiswing/components/menu.html#create), RootPane (my view, correct me if I wrong) is bridge betweens Native OS and Java Graphics Toolkit (AWT) – mKorbel Oct 27 '12 at 10:07
  • Uh, i'm not sure about that either. But the example you gave me @mKorbel used the JMenuBar in the same way as i did, but instead of adding it directly, i made a multilayered Frame after which i added the JMenuBar in the finaltop layer. I do this because i thought that in this way it would be easier to keep the JMenuBar of the JFrame displayed even if the JDialog gained focus. But I dont know if I have to use a JRootPane to accomplish what i requested, but i tried alot of different things and the JRootPane was the last one I tried, so sorry if it confused you. – Triplle Oct 27 '12 at 10:59
  • But isnt there a much easier way to let a JDialog that is invoked from a JFrame show the same JMenuBar as the JFrame? – Triplle Oct 27 '12 at 11:01

2 Answers2

2

One key to solving this problem, pun intended, is to let a key binding share a common menu action, as shown below. Note how a menu item, your dialog's content and an (otherwise superfluous) button can all use the same Action instance. A few additional notes:

  • Kudos for using getMenuShortcutKeyMask().

  • Swing GUI objects should be constructed and manipulated only on the event dispatch thread (EDT).

  • System properties should be set before starting the EDT.

  • Make the dialog's setLocation() relative to the frame after its geometry is known.

  • A common Mac idiom uses the following predicate:

    if (System.getProperty("os.name").startsWith("Mac OS X") {…}
    
  • See also this example.

  • For local use in the dialog itself, also consider JToolBar.

MenuBarProblem with menu

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.KeyStroke;

/**
 * @see https://stackoverflow.com/a/13100894/230513
 */
public class MenuBarProblem extends JFrame {

    private static final int MASK =
        Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
    private static final String exitName = "Exit";
    private static final KeyStroke exitKey =
        KeyStroke.getKeyStroke(KeyEvent.VK_W, MASK);
    private final ExitAction exitAction = new ExitAction(exitName);

    public MenuBarProblem() {
        super("Frame");
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        JMenu fileMenu = new JMenu("File");
        JMenuItem fileExit = new JMenuItem(exitAction);
        fileMenu.add(fileExit);
        JMenuBar menu = new JMenuBar();
        menu.add(fileMenu);

        JDialog d = new JDialog(this, "Dialog");
        JPanel p = new JPanel();
        p.getInputMap().put(exitKey, exitName);
        p.getActionMap().put(exitName, exitAction);
        p.add(new JButton(exitAction));
        d.add(p);
        d.pack();
        d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);

        this.setJMenuBar(menu);
        this.pack();
        this.setSize(new Dimension(320, 240));
        this.setLocationByPlatform(true);
        this.setVisible(true);
        d.setLocation(this.getRootPane().getContentPane().getLocationOnScreen());
        d.setVisible(true);
    }

    private static class ExitAction extends AbstractAction {


        public ExitAction(String name) {
            super(name);
            this.putValue(Action.MNEMONIC_KEY, exitKey.getKeyCode());
            this.putValue(Action.ACCELERATOR_KEY, exitKey);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            System.exit(0);
        }
    }

    public static void main(String[] args) {
        System.setProperty("apple.laf.useScreenMenuBar", "true");
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new MenuBarProblem();
            }
        });
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Extremely usefull information alrady. Thanks for these tips. I will work on these in short time. First have to finish the exams ;) – Triplle Oct 30 '12 at 19:24
  • I'm encountering yet another problem... When i copy paste the code given above. I still dont have a menubar when the focus is on the dialog. The weird thing is that in the screenshot above the code, there is a menubar even when the focus is on the dialog. So any idea what causes this problem? – Triplle Nov 06 '12 at 08:34
  • You're using a different version than I am. I can't think of a reason to hide the menu bar when a _modeless_ dialog is active. – trashgod Nov 06 '12 at 10:53
0

Solved!

Using a JFrame with the use of setAlwaysOnTop(true) gives me the desired effect of having a JMenuBar when the focus changes.

Triplle
  • 99
  • 1
  • 6