我在java中制作游戏,我需要弄清楚如何相对于最大化大小调整JFrame的大小。在阅读了充满了Eel的回应的Hovercraft并玩了一些之后,我更新了代码。这应该是一个最小,完整和可验证的例子:
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);
}
}
我在Linux上开发,这是我得到的输出:
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
当我将其设置为非最大化尺寸时,帧大小是正确的,但如果我使其最大化,我第一次检查帧大小时它没有显示差异。它仅在我第二次设置并查询时显示。
奇怪的是,如果我连续两次设置它
if (w == 0 && h == 0) {
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
} else {
然后它永远不会更新帧大小,无论我调用它多少次。如果我连续三次设置它就可以了。也许这是一次切换?
即使更奇怪,ContentPane的大小也会落后于帧大小,这意味着它会在两次尝试时落后于最大化的大小。
在玩这个程序时,我设法获得了一个在连续运行中随机运行的组合,有时会立即更新,有时则不会。这让我想到也许在EDT中有一个线程计时的事情,也许这是一个懒惰的更新,但添加更长的睡眠并没有帮助。
在Windows上,输出为:
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
此处JFrame大小正确,但ContentPane仍然滞后于该帧。
答案 0 :(得分:1)
当我运行此代码时,我没有得到预期的结果:
这是预期的结果,因为你在渲染JFrame之前调用方法,当它的大小实际上是0,0时。至于preferredSize - 很难说没有更多的信息。尝试渲染后打印出来。
例如:
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);
}
});
}
}
哪个输出:
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]
请注意,preferredSize与渲染大小无关,而与添加的组件和布局管理器有关。
答案 1 :(得分:1)
我不认为内容窗格是这样的。我可能错了,但我更喜欢使用自己的绘图面板(JPanel)。
我创建了一个绘图面板和一个JFrame。创建绘图面板和JFrame后,我将JFrame设置为NORMAL或MAXIMIZED_BOTH。这更准确地模拟了游戏从正常切换到最大化并恢复正常。
最后,我为尺寸测试创建了一个单独的Runnable类。以下是Windows 8.1的结果。如果有人可以在Linux上运行此代码,我会很感激。
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
主要区别在于我使用窗口状态监听器来检测JFrame大小何时发生变化,并使用绘图面板的首选大小来获取正确的内容大小。
在panel.setPreferredSize方法调用之后,基于JFrame大小更改修改绘图面板的代码将放在windowStateChanged方法中。
以下是代码:
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);
}
}
});
}
}
}
答案 2 :(得分:0)
如果您需要MAXIMIZED尺寸,请写下
setExtendedState(JFrame.MAXIMIZED_BOTH);
如果你想要正常尺寸
setExtendedState(JFrame.NORMAL);