I am making a game in java, and I need to figure out how to resize the JFrame relative to the maximized size. After reading Hovercraft full of Eel's responses and playing with it some more, I have updated the code. This should be a minimal, complete and verifiable example:
import java.awt.Dimension;
import javax.swing.*;
import java.awt.Toolkit;
import java.lang.reflect.InvocationTargetException;
public class MyFrameTest {
JFrame frame;
public static void main(String[] args) {
new MyFrameTest();
}
public MyFrameTest() {
System.out.println("screenSize: " + Toolkit.getDefaultToolkit().getScreenSize());
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
}
});
}
catch (Exception e) { System.out.println("invokeAndWait exception: "+e); }
set_size(300,300);
set_size(500,500);
set_size(0,0);
set_size(0,0);
set_size(500,500);
set_size(0,0);
set_size(0,0);
System.exit(0);
}
public void set_size(int width, int height) {
final Dimension d = new Dimension(width, height);
final int w = width;
final int h = height;
try { Thread.sleep(500); } catch (InterruptedException e) { }
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
if (w == 0 && h == 0) {
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
} else {
frame.setExtendedState(JFrame.NORMAL);
frame.setSize(d);
}
displaySize(frame, w, h);
}
});
} catch (Exception e) { System.out.println("invokeAndWait exception: "+e); }
}
public void displaySize(JFrame frame, int width, int height) {
Dimension df = frame.getSize();
Dimension dc = frame.getContentPane().getSize();
if (width == 0 && height == 0)
System.out.printf("Size maximized : Frame %4d,%-4d : Content %4d,%-4d\n",
df.width, df.height, dc.width, dc.height);
else
System.out.printf("Size %4d,%-4d : Frame %4d,%-4d : Content %4d,%-4d\n",
width, height, df.width, df.height, dc.width, dc.height);
}
}
I am developing on Linux, and this is the output I get:
screenSize: java.awt.Dimension[width=1920,height=1080]
Size 300,300 : Frame 300,300 : Content 2,1
Size 500,500 : Frame 500,500 : Content 292,270
Size maximized : Frame 500,500 : Content 492,470
Size maximized : Frame 1928,1033 : Content 1920,1003
Size 500,500 : Frame 500,500 : Content 1920,1003
Size maximized : Frame 500,500 : Content 492,470
Size maximized : Frame 1928,1033 : Content 1920,1003
When I set it to a non-maximized size, the frame size is correct, but if I make it maximized, the first time I check the frame size it shows no difference. It only shows up the second time I set it and query it.
Weirdly, if I set it twice in a row like this
if (w == 0 && h == 0) {
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
} else {
then it NEVER updates the frame size no matter how many times I called it. If I set it three times in a row it works. Maybe it is a toggle?
Even weirder, the ContentPane size lags the frame size, which means it lags the maximized size by TWO tries.
While playing with the program I managed to get one combination that was behaving randomly on successive runs, sometimes it updates immediately and sometimes it does not. This makes me think maybe there is a thread timing thing going on in the EDT, maybe it is a lazy update, but adding a longer sleep does not help.
On Windows the output is:
screenSize: java.awt.Dimension[width=1600,height=900]
Size 300,300 : Frame 300,300 : Content 116,0
Size 500,500 : Frame 500,500 : Content 284,262
Size maximized : Frame 1616,854 : Content 484,462
Size maximized : Frame 1616,854 : Content 1600,816
Size 500,500 : Frame 500,500 : Content 1600,816
Size maximized : Frame 1616,854 : Content 484,462
Size maximized : Frame 1616,854 : Content 1600,816
Here the JFrame size is correct but the ContentPane still lags the frame.
When I run this code though, I do not get the expected result:
It is the expected result because you're calling the methods before the JFrame has been rendered, when its size is in fact 0, 0. As for the preferredSize -- hard to say without more information. Try printing this out after rendering.
For example:
import java.awt.Dimension;
import javax.swing.*;
public class MyFrameTest {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
displaySizes(frame, "Before");
frame.setVisible(true);
// to place this onto the event queue and so delay its calling until after
// the JFrame has been rendered
SwingUtilities.invokeLater(new Runnable() {
public void run() {
displaySizes(frame, "After");
}
});
}
private void displaySizes(final JFrame frame, String when) {
Dimension size = frame.getContentPane().getSize();
Dimension preferredSize = frame.getContentPane().getPreferredSize();
System.out.println(when + " Rendering");
System.out.println("Size: " + size);
System.out.println("Pref Size: " + preferredSize);
}
});
}
}
Which outputs:
Before Rendering
Size: java.awt.Dimension[width=0,height=0]
Pref Size: java.awt.Dimension[width=0,height=0]
After Rendering
Size: java.awt.Dimension[width=1680,height=988]
Pref Size: java.awt.Dimension[width=0,height=0]
Note that the preferredSize has nothing to do with the rendered size and all to do with the components added and layout managers used.
I don't think that a content pane works like that. I could be wrong, but I prefer to use my own drawing panel (JPanel).
I created a drawing panel and a JFrame. After creating the drawing Panel and JFrame, I set the JFrame to either NORMAL or MAXIMIZED_BOTH. This more accurately simulates a game switching from normal to maximized and back to normal.
Finally, I created a separate Runnable class for the size test. Here are the results from Windows 8.1. If anyone can run this code on Linux, I'd appreciate it.
screenSize: java.awt.Dimension[width=1600,height=900]
Frame 1616,876 : Content 1600,837
Frame 416,439 : Content 400,400
Frame 1616,876 : Content 1600,837
Frame 416,439 : Content 400,400
Frame 1616,876 : Content 1600,837
The main differences are that I used a window state listener to detect when the JFrame size changed, and I used the preferred size of the drawing panel to get the correct content size.
The code to modify your drawing panel based on a size change of the JFrame would go in the windowStateChanged method, after the panel.setPreferredSize method call.
Here's the code:
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.WindowEvent;
import java.awt.event.WindowStateListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class FrameResizeTesting implements Runnable {
private Dimension frameSize;
private Dimension panelSize;
private Dimension screenSize;
private JFrame frame;
public static void main(String[] args) {
SwingUtilities.invokeLater(new FrameResizeTesting());
}
public FrameResizeTesting() {
this.screenSize = Toolkit.getDefaultToolkit().getScreenSize();
System.out.println("screenSize: " + this.screenSize);
}
@Override
public void run() {
final DrawingPanel panel = new DrawingPanel();
frame = new JFrame("Frame Resizing Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addWindowStateListener(new WindowStateListener() {
@Override
public void windowStateChanged(WindowEvent event) {
Dimension d = frame.getSize();
d.width = d.width - frameSize.width + panelSize.width;
d.height = d.height - frameSize.height + panelSize.height;
panel.setPreferredSize(d);
panel.invalidate();
displaySize(panel);
}
});
frame.add(panel);
frame.pack();
panelSize = panel.getSize();
frameSize = frame.getSize();
frame.setVisible(true);
new Thread(new ResizingRunnable()).start();
}
private void displaySize(DrawingPanel panel) {
Dimension df = frame.getSize();
Dimension dc = panel.getPreferredSize();
System.out.printf("Frame %4d,%-4d : Content %4d,%-4d\n", df.width,
df.height, dc.width, dc.height);
}
public class DrawingPanel extends JPanel {
private static final long serialVersionUID = 124082399133852883L;
public DrawingPanel() {
this.setPreferredSize(new Dimension(400, 400));
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
public class ResizingRunnable implements Runnable {
@Override
public void run() {
set_size(false);
set_size(true);
set_size(false);
set_size(true);
set_size(false);
set_size(true);
set_size(true);
System.exit(0);
}
private void set_size(final boolean isExtended) {
try {
Thread.sleep(500L);
} catch (InterruptedException e) {
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (isExtended) {
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
} else {
frame.setExtendedState(JFrame.NORMAL);
}
}
});
}
}
}
If you need the MAXIMIZED size, write this
setExtendedState(JFrame.MAXIMIZED_BOTH);
If you want the NORMAL size
setExtendedState(JFrame.NORMAL);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.