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()));
......
精彩评论