开发者

Why jframe hides taskbar when maximized?

I'm using setUndecorated(true); and getRootPane().setWindowDecorationStyle(JRootPane.FRAME); in my jFrame. This works great but now when I maximized my frame it spreads all over the window even taskbar is not visible. What can I do to make frame not to hide taskbar?

Also when I maximize minimize my frame mu开发者_高级运维ltiple times the cursor is changed to this <-> which is generally used change size of frame when cursor is on the border of frame. Is there anything I can do for this?


A small code then can reproduce the thing:

import javax.swing.JFrame;
import javax.swing.JRootPane;
public class Demo extends JFrame {
    public Demo() {
        setSize(250,125);
        setUndecorated(true);
        getRootPane().setWindowDecorationStyle(JRootPane.FRAME);
        setVisible(true);
    }
    public static void main(String[] args) {
        new Demo();
    }
}


This is a known bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4737788

Quote from this link:

A workaround is to subclass JFrame and override the setExtendedState method, catching any maximize events before they happen and setting the maximum bounds of the frame appropriately before calling the superclass's setExtendedState method.

import java.awt.*;
import javax.swing.*;

public class PFrame extends JFrame
{
private Rectangle maxBounds;

public PFrame()
{
    super();        
    maxBounds = null;
}

//Full implementation has other JFrame constructors

public Rectangle getMaximizedBounds()
{
    return(maxBounds);
}

public synchronized void setMaximizedBounds(Rectangle maxBounds)
{
    this.maxBounds = maxBounds;
    super.setMaximizedBounds(maxBounds);
}

public synchronized void setExtendedState(int state)
{       
    if (maxBounds == null &&
        (state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH)
    {
        Insets screenInsets = getToolkit().getScreenInsets(getGraphicsConfiguration());         
        Rectangle screenSize = getGraphicsConfiguration().getBounds();
        Rectangle maxBounds = new Rectangle(screenInsets.left + screenSize.x, 
                                    screenInsets.top + screenSize.y, 
                                    screenSize.x + screenSize.width - screenInsets.right - screenInsets.left,
                                    screenSize.y + screenSize.height - screenInsets.bottom - screenInsets.top);
        super.setMaximizedBounds(maxBounds);
    }

    super.setExtendedState(state);
}
}


Fortega answer worked however, some part is not needed (or no longer needed with Java 8):

  • The Rectangle does not need to be saved.
  • The code does not take into account dual screen configuration. In particular, the GraphicsConfiguration will change if the window change screen.
  • As far as I tested, the only required override is setExtendedState.

When factoring dual screen configuration, at least on Windows, the below code does not work as intended:

Rectangle maxBounds = new Rectangle(screenInsets.left + screenSize.x, 
                                    screenInsets.top + screenSize.y, 
                                    screenSize.x + screenSize.width - screenInsets.right - screenInsets.left,
                                    screenSize.y + screenSize.height - screenInsets.bottom - screenInsets.top);

On the following dual screen set up:

  • Left screen 1920x1080 (not primary), position: -1920, 0
  • Right screen 1920x1080 (primary), position: 0, 0

The maxBounds will contains negative x (-1920) but the setMaximizedBounds is somehow expecting a coordinate in the screen space (where (x,y) starts at (0,0)) , not the virtual screen:

  • It will set to setMaximizedBounds(x=-1920,y=0,width=1920,height=1050)
  • Windows will see the window on the left screen (because I have one taskbar per screen showing only window on that screen) however the window won't be shown on the screen because it is off bounds.
  • If the resolution of the screen, or worse, its scale factor (with a laptop, Windows 10 will apply a scale factor, ex: 25%, making the screen "not so" 1920x1080), then the above code does not adapt. For example, if my configuration have 3 screens with the right most being the primary, the window will badly display on the left and middle screen. I don't think I fixed this in the below code.

The following code work on Windows, with dual screen:

  @Override
  public synchronized void setExtendedState(final int state) {
    if ((state & Frame.MAXIMIZED_BOTH) == Frame.MAXIMIZED_BOTH) {
      final GraphicsConfiguration cfg = getGraphicsConfiguration();
      final Insets screenInsets = getToolkit().getScreenInsets(cfg);
      final Rectangle screenBounds = cfg.getBounds();
      final int x = screenInsets.left + screenBounds.x * 0;
      final int y = screenInsets.top + screenBounds.y * 0;
      final int w = screenBounds.width - screenInsets.right - screenInsets.left;
      final int h = screenBounds.height - screenInsets.bottom - screenInsets.top;
      final Rectangle maximizedBounds = new Rectangle(x, y, w, h);

      System.out.println("cfg (" + cfg + ") screen.{bounds: " + screenBounds + ", insets: " + screenInsets + ", maxBounds: " + maximizedBounds);

      super.setMaximizedBounds(maximizedBounds);
    }
    super.setExtendedState(state);
  }

On a simple JFrame:

  • Maximizing on the left screen ("screen=0") will print cfg (D3DGraphicsConfig[dev=D3DGraphicsDevice[screen=0],pixfmt=0]) screen.{bounds: java.awt.Rectangle[x=-1920,y=0,width=1920,height=1080], insets: java.awt.Insets[top=0,left=0,bottom=30,right=0], maxBounds: java.awt.Rectangle[x=0,y=0,width=1920,height=1050]
  • Maximizing on the right screen ("screen=1") will print cfg (D3DGraphicsConfig[dev=D3DGraphicsDevice[screen=1],pixfmt=0]) screen.{bounds: java.awt.Rectangle[x=0,y=0,width=1920,height=1080], insets: java.awt.Insets[top=0,left=0,bottom=30,right=0], maxBounds: java.awt.Rectangle[x=0,y=0,width=1920,height=1050]


Maybe you can set the maximum size of the jFrame and restrict it according to the screen size.

EDIT

Also check out setExtendedState


Starting from Fortega answer, you can make it work even with 125% screen sizi adding

Rectangle screenSize = getGraphicsConfiguration().getBounds();
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
screenSize.setSize(new Dimension(gd.getDisplayMode().getWidth(), gd.getDisplayMode().getHeight()));
......
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜