Creating an offscreen frame in Java (or: how to avoid a blank menu on a Mac, when all application windows are closed)?
Asked Answered
B

6

6

I am making a Mac application, and I want my menu bar to look right.

Any Mac user knows the menu bar should be in the top screen menu. Setting apple.laf.useScreenMenuBar to true in the property list file gets rid of the in-frame menu bars and moves the menu bar of the current focused window to the screen menu.

However, when all windows are hidden or when there are no windows, there are no menu bars to move to the top, and you just get a blank menu. I heard a solution to this was to create an offscreen window that is focused when no others are. The only purpose of it would be its menu, so that it could fill in when the others are gone.

However, I've been getting loads of problems. I can't seem to move the window off the screen because Macs won't let you set the coordinates to something past the size of the screen; it just cuts it off and positions it at the edge instead. Is there something else I have to do to make an offscreen window?

Bazar answered 2/2, 2010 at 17:19 Comment(0)
T
4

You should definitely consider WizardOfOdds' very helpful answer. Using "The Application Menu" correctly will help, and it's easy to set up a minimal Info.plist to get started. A persistent File menu will allow your application to open a new window when others are closed. This answer links to a simple example.

Although Apple's Human Interface Guidelines are an excellent guide to what your users will expect, you can certainly experiment with the approach you suggested in your question. In particular, you might try setLocation(Short.MIN_VALUE, Short.MIN_VALUE) on the invisible window. In addition, you might want to respond to a WindowEvent in some special way if it signals the close of the last visible window.

Addendum: When your listener sees the last visible window close, create a new, empty application window. Alternatively, move the invisible window onscreen and make it visible until the user decides how to proceed.

Addendum: Mac OS X helpfully prevents a visible window form being moved offscreen, but it's easy to put an invisible window in limbo, as shown below.

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JToggleButton;

public class FrameTest extends JFrame {

    private static FrameTest marco;
    private static FrameTest polo;

    private static class MyPanel extends JPanel {

        public MyPanel() {
            super(true);
            final JToggleButton b = new JToggleButton("Test");
            b.addItemListener(new ItemListener() {
                @Override
                public void itemStateChanged(ItemEvent e) {
                    if (b.isSelected()) {
                        polo.setLocation(100, 100);
                        polo.setVisible(true);
                    }
                    else {
                        polo.setVisible(false);
                        polo.setLocation(Short.MIN_VALUE, Short.MIN_VALUE);
                    }
                }
            });
            this.add(b);
        }
    }

    public FrameTest(String title) {
        super(title);
        this.setLayout(new BorderLayout());
        this.add(new MyPanel());
        this.pack();
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    public static void main(final String[] args) {

        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                marco = new FrameTest("Marco");
                marco.setLocationRelativeTo(null);
                marco.setVisible(true);
                polo = new FrameTest("Polo");
                polo.setLocation(Short.MIN_VALUE, Short.MIN_VALUE);
            }
        });
    }
}
Tadashi answered 3/2, 2010 at 0:57 Comment(5)
Just like the question asker, I fail to see how the article WizardOfOdds referenced can help. Also, the question asker seems to have a specific problem: I can't seem to move the window off the screen because Macs won't let you set the coordinates to something past the size of the screenDissonance
@Arjan: thanks for the edit; how did you get the more focused link? The article refers the reader to the Xcode examples in /Developer/Examples/Java. I've added an example of moving a window offscreen.Tadashi
I just did an "Inspect element" for the heading in my browser, and that revealed an anchor: <a name="//apple_ref/doc/uid/TP40001909-211936" [..]>. (Some other web pages specify an id for each heading, and ids can be used for anchors as well.) (Good example, by the way.)Dissonance
This answer is not helpful; because a non-visisble Frame cannot have a menubar. The goal is to have a menu bar visible when there are no visible windows.Tropophilous
Mac applications do this, so it's not unexpected. I wonder if JDesktopPane might be an alternative.Tadashi
C
1

I know that this post is quite old, anyway, I had the same problem and found the solution. Actually it's quite simple. Just don't add the JMenuBar to your main frame when running on mac os x, but to your application using

com.apple.eawt.Application.getApplication().setDefaultMenuBar(menuBar);

Now the MenuBar is still displayed even if you set all frame's visibility to false.

Crossman answered 10/8, 2012 at 17:11 Comment(0)
M
0

First a note: your question seems really to be "How to have a Window menu following the Apple Human Interface Guidelines" and not "creating an offscreen frame in Java", which seems like a monstrous hack.

I suggest checking Apple's "Mac OS X Integration for Java", which, under "Window menu", shows apparently exactly what you're trying to achieve:

Apple Human Interface Guidelines suggests that all Mac OS X applications should provide a Window menu to keep track of all currently open windows. A Window menu should contain a list of windows, with a checkmark next to the active window.

Misreport answered 2/2, 2010 at 18:6 Comment(3)
Hey... Um... Did you actually read my question? I kind of asked how to get around the problem where the screen menu disappears when no windows are open in Java... I said nothing at all about the Apple Human Interface Guidelines.Bazar
From that link: Removing menus from your windows and putting them in the menu bar is highly encouraged, but that approach does not perfectly emulate the native experience of Mac OS X menus. In Mac OS X, a native application’s menu bar is always visible when an application is the active application, whether or not any windows are currently open. In Java for Mac OS X, the menus in the menu bar are associated with a top-level frame, and the menus will disappear if the frame closes.Dissonance
Arjan, I know, that's my problem, I need to create a window that people can't see to hold the menu.Bazar
D
0

Not a direct solution, but I think some create a 1-pixel window instead. That yields complaints though, like one described at Super User: Chaotic behavior of a dead pixel on my iMac 24"...

Dissonance answered 2/2, 2010 at 22:8 Comment(4)
Interesting article, but I'm missing the connection.Tadashi
I think the connection is that should you create a visible 1x1 window hack, then to some it may look like a chaotic dead pixel because if it's "visible", it's on screen (as opposed to setVisible(false) that can be located offscreen).Misreport
Ah, a possum pixel, just playing dead :-)Tadashi
Well, all of the other answers have just left me confused, so I tried this. Macs cap the size of windows too! It won't let me make the window smaller than the height of the title bar and the width of maybe 50 to hundred pixels, I'm not sure. I feel so stupid, from all the other answers it looks like the solution is probably right in front of me, but I can't see it... It's so hard programming when you're fourteen... Or maybe I just suck.Bazar
B
0

This is a comment to trashgod's answer. It's too big so I have to move it here >.<


More problems!

I'm getting 2 errors:

line 23: The method itemStateChanged(ItemEvent) of type new ItemListener(){} must override a superclass method

line 50:The method run() of type new Runnable(){} must override a superclass method

Any help? I've never encountered this before. I don't know what it means.

EDIT: I have more problems! I need the offscreen window to be visible while it is offscreen for it to produce a menu to move to the screen menu bar. When I use the code

offScreen = new JFrame("WTF?!  You can see me?");
offScreen.setSize(400,300);
offScreen.setLocation(0, java.awt.Toolkit.getDefaultToolkit().getScreenSize().height+50);
System.out.println(offScreen.getLocation());
offScreen.setVisible(true);
System.out.println(offScreen.getLocation());

I get the output:

java.awt.Point[x=0,y=1100]
java.awt.Point[x=0,y=961]

It moves it back once it's made visible again!

I've searched for ages and I can't find anything.

Bazar answered 3/2, 2010 at 17:16 Comment(1)
This is the expected behavior. I've edited my answer and added a link to a simple, platform-independent example that may guide you. Also, you can edit your question to include new findings.Tadashi
T
0

This code works in Java 7:

if( isMac ) {
    //This creates an invisible frame so that we always have a menu bar visible
    JFrame menuFrame = new JFrame();
    menuFrame.setUndecorated( true );
    menuFrame.setJMenuBar( defaultMenuBar );
    AWTUtilities.setWindowOpaque( menuFrame, false );
    menuFrame.setBounds( 0,0,1,1 );
    menuFrame.setVisible( true );
}

Just call this before you open any other windows, and it will stay in the background and automatically become the focused window when others are closed. You can still use the com.apple.eawt.Application.getApplication().setDefaultMenuBar(menuBar) method in your application so that you don't need to call setJMenuBar() on each JFrame.

Tropophilous answered 1/3, 2013 at 16:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.