Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does JFrame.setExtendedState(MAXIMIZED_BOTH) work with undecorated frames?

Tags:

java

swing

winapi

The following Swing code doesn't work correctly on my machine or my co-workers machines (all Windows XP & Java 6):

public class Test {
    public static void main(String[] args) {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(800, 600);
        frame.setLayout(new FlowLayout());
        frame.add(new JButton(new AbstractAction("Maximize") {
            @Override
            public void actionPerformed(ActionEvent e) {
                frame.setExtendedState((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH ? JFrame.NORMAL : JFrame.MAXIMIZED_BOTH);
            }
        }));
        frame.setUndecorated(true);
        frame.setVisible(true);
    }
}

It maximizes the window, but does not take into consideration the windows task bar (it fills the screen). If you comment out "frame.setUndecorated(true);" it seems to work correctly.

The Javadoc seems to imply this should work. Is this a bug in Java? Is it limited to a specific release, or version of Windows? Is there a workaround?

I've seen a few workarounds, but they seem incomplete. I can't be the first person to code my own frame decorations in Java.

EDIT: After downloading the OpenJDK and digging through the native code, I found that Java is calling the win32 function SetWindowPlacement and under some conditions altering MINMAXINFO to get the right window size. I think what I was seeing was the default windows behavior for a window with no title or border (although I can't find that documented anywhere). I've found that calling JFrame.setMaximizedBounds() provides the bounds used to alter the win32 MINMAXINFO structure. So by altering my action performed and using the window size suggested by camickr as my MaximizedBounds, I get a bit closer:

GraphicsConfiguration graphicsConfiguration = frame.getGraphicsConfiguration();
frame.setMaximizedBounds(graphicsConfiguration.getBounds());
frame.setExtendedState((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH ? JFrame.NORMAL : JFrame.MAXIMIZED_BOTH);

Now the maximize window no longer hides the menubar. But.. now I have another problem. I can't maximize from a secondary monitor. The frame just disappears.

I'm adding some win32 tags in hopes of getting a C++ programmer who recognizes this problem.

SOLUTION: I apparently can't answer my own question yet, so I'll just put my solution here. I had to use a Sun class, and I haven't tested it on any platforms other than Windows, but so far this seems to be working well with multiple monitors, and multiple taskbar configurations:

GraphicsConfiguration config = frame.getGraphicsConfiguration();
Rectangle usableBounds = SunGraphicsEnvironment.getUsableBounds(config.getDevice());
frame.setMaximizedBounds(new Rectangle(0, 0, usableBounds.width, usableBounds.height));
frame.setExtendedState((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH ? JFrame.NORMAL : JFrame.MAXIMIZED_BOTH);
like image 959
Bryan Young Avatar asked Sep 13 '11 14:09

Bryan Young


1 Answers

Interesting. When I try it it seems to happen in two steps. First expands to fill the space above the task bar, then a split second later it covers the task bar. I have no idea why.

Anyway for a workaround you can use:

GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
Rectangle bounds = env.getMaximumWindowBounds();
System.out.println("Screen Bounds: " + bounds );

to manually set the bounds of your frame when you want to maximize it.

like image 198
camickr Avatar answered Nov 08 '22 19:11

camickr