Java Swing Frame 有点不对劲?

Java Swing Frame is a tad off?

我有一个简单的动画代码,可以创建一个仪表类型的矩形效果。我想创建它以使其完全填满面板。我离得太近了,但它延伸到了底部的框架之外。我错过了什么?

public class Main {

public static void main(String[] args) {

    JFrame frame = new JFrame("Pong");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new GridLayout(1,2));
    frame.setSize(500, 500);

    //MouseTest test = new MouseTest();
    Test test2 = new Test(frame.getWidth(), frame.getHeight(), frame.getHeight(), 50);
    //frame.add(test);
    frame.add(test2);

    frame.setVisible(true);

    }
}

public class Test extends JPanel implements ActionListener, MouseListener{

int y = 0, width, height, dy=0, maxHeight;
int BOTTOM;
Timer timer;

public Test(int width, int height, int BOTTOM, int SPEED){
    setBackground(Color.BLUE);
    this.width = width;
    maxHeight = height;
    this.BOTTOM = BOTTOM;

    addMouseListener(this);

    timer = new Timer(1000/SPEED, this);
    timer.start();

   }
 public void move(){

    if(y>=maxHeight){
        dy = -1;
    }
    if(y<=0)
    {
        dy = 1;
    }
    y+=dy;
    height+=dy;
    //System.out.println(y);
    repaint();

}

public void paintComponent(Graphics g){

    super.paintComponent(g);
    if(y<=maxHeight/2) {
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height);
    }
    if(y>=maxHeight/2 && y<(maxHeight/10)*9){
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM-(maxHeight/2), width, maxHeight/2);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height-(maxHeight/2));
    }
    if(y>=(maxHeight/10)*9){
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM-(maxHeight/2), width, maxHeight/2);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM-(9*(maxHeight/10)), width, (4*maxHeight)/10);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height-(9*(maxHeight)/10));
    }
        for(int i = 1; i<6; i++)
            g.fillRect(0, BOTTOM - (i*(maxHeight/5)), width, 10);

    System.out.println(y);



}

您的面板占用的空间少于 JFrame,因为您的框架有标题栏和 window 边框。您可以在您的绘画方法中查询 'JPanel' 与您的 JPanelgetWidth()getHeight() 使用的正确宽度和高度(换句话说,您的 JFrame 的宽度和高度与您的 JPanel 的宽度和高度不同,即使 JPanel 在边框之间视觉上占据了框架内的所有 space。

或者,如果您确实有不可能做到这一点的逻辑,您可以查询 insets of the frame 的大小,并从宽度中减去左右插入值,并将其作为宽度传递,并使用顶部和底部插入值对高度执行相同操作。

另一种方法是使用 pack()。它将框架的大小设置为框架内容的大小。在您的代码中,它看起来像这样:

frame.add(test2);
frame.pack();

如果您这样做,则不需要 frame.setSize() 调用。您可以使用 .add() 添加面板,也可以使用:

frame.setContentPane(test2);

所以我结合了您的评论并使其正常工作。这是有效的代码。

public class Main {

public static void main(String[] args) {

    JFrame frame = new JFrame("Pong");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new GridLayout(1,2));
    Insets inset = frame.getInsets();


    Test test2 = new Test(200-(inset.right + inset.left), 200 -(inset.top + inset.bottom), 200, 50);
    frame.setContentPane(test2);
    frame.pack();

    frame.setVisible(true);

}
}

public class Test extends JPanel implements ActionListener, MouseListener{

int y = 0, width, height, dy=0, maxHeight;
int BOTTOM;
Timer timer;
Dimension size;
Insets inset;

public Test(int width, int height, int BOTTOM, int SPEED){
    size = new Dimension(width, height);
    setBackground(Color.BLUE);
    setPreferredSize(size);
    inset = this.getInsets();
    this.width = width-(inset.right+inset.left);
    maxHeight = height;
    this.BOTTOM = BOTTOM - (inset.bottom+inset.top);

    addMouseListener(this);

    timer = new Timer(1000/SPEED, this);
    timer.start();

   }
public void move(){

    if(y>=maxHeight){
        dy = -1;
    }
    if(y<=0)
    {
        dy = 1;
    }
    y+=dy;
    height+=dy;
    //System.out.println(y);
    repaint();

}

public void paintComponent(Graphics g){

    super.paintComponent(g);
    if(y<=maxHeight/2) {
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height);
    }
    if(y>=maxHeight/2 && y<(maxHeight/10)*9){
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - (maxHeight / 2), width, maxHeight / 2);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height-(maxHeight/2));
    }
    if(y>=(maxHeight/10)*9){
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM-(maxHeight/2), width, maxHeight/2);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM-(9*(maxHeight/10)), width, (4*maxHeight)/10);
        g.setColor(Color.green);
        g.fillRect(0, BOTTOM - y, width, height-(9*(maxHeight)/10));
    }

    g.setColor(Color.white);
        for(int i = 1; i<6; i++)
            g.fillRect(0, BOTTOM - (i*(maxHeight/5)), width, 5);

    }
  • 覆盖 getPreferredSizeJPanel,这将有助于布局管理器确定布局组件的最佳方式
  • 使用 JFrame#pack 将框架边框环绕视图
  • 使用getWidthgetHeight 获取面板的实际大小。当您需要知道这些值时,您应该这样做,不要长时间存储它们,因为这些值可能会改变
  • 你也应该通读一下Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?

这是基于您的代码的基本示例...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test1 {

    public static void main(String[] args) {
        new Test1();
    }

    public Test1() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private int yPos;
        private int dy = 1;
        private int bottom = 50;

        public TestPane() {
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    move();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(500, 500);
        }

        public void move() {

            if (yPos >= getHeight()) {
                dy = -1;
            }
            if (yPos <= 0) {
                dy = 1;
            }
            yPos += dy;
            repaint();

        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int maxHeight = getHeight();
            int width = getWidth();
            int height = maxHeight;
            if (yPos <= maxHeight / 2) {
                g.setColor(Color.green);
                g.fillRect(0, bottom - yPos, width, height);
            }
            if (yPos >= maxHeight / 2 && yPos < (maxHeight / 10) * 9) {
                g.setColor(Color.green);
                g.fillRect(0, bottom - (maxHeight / 2), width, maxHeight / 2);
                g.setColor(Color.green);
                g.fillRect(0, bottom - yPos, width, height - (maxHeight / 2));
            }
            if (yPos >= (maxHeight / 10) * 9) {
                g.setColor(Color.green);
                g.fillRect(0, bottom - (maxHeight / 2), width, maxHeight / 2);
                g.setColor(Color.green);
                g.fillRect(0, bottom - (9 * (maxHeight / 10)), width, (4 * maxHeight) / 10);
                g.setColor(Color.green);
                g.fillRect(0, bottom - yPos, width, height - (9 * (maxHeight) / 10));
            }
            for (int i = 1; i < 6; i++) {
                g.fillRect(0, bottom - (i * (maxHeight / 5)), width, 10);
            }

        }
    }

}