如何相对于最大化大小调整JFrame的大小

时间:2015-09-05 18:47:54

标签: java swing

我在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仍然滞后于该帧。

3 个答案:

答案 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);