JFrame getHeight() and getWidth() return 0



我正在制作一个简单的乒乓球游戏;一部分碰撞力学需要获得画布的宽度和高度才能重定向。但是,出于某种原因,getWidth()getHeight()返回0。这是代码的主要块。

package pong;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main extends JPanel {
    static int gameSpeed = 10;
    Ball ball = new Ball(this);
    private void move() {
        ball.move();
    }
    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g;
        ball.paint(g2d);
    }
    public static void main(String args[]) throws InterruptedException {
        JFrame frame = new JFrame("Pong");
        Main game = new Main();
        frame.add(game);
        frame.setSize(400, 400);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        while (true) {
            game.move();
            game.repaint();
            Thread.sleep(gameSpeed);
        }
    }
}

这是处理运动条件的实际Ball类。

package pong;
import javax.swing.*;
import java.awt.*;
public class Ball extends JPanel {
    int x = 1;
    int y = 1;
    int dx = 1;
    int dy = 1;
    private Main game;
    public Ball(Main game) {
        this.game = game;
    }
    void move() {
        System.out.println(getWidth() + getHeight());
        if (x + dx < 0) {
            dx = 1;
        }
        if (y + dy < 0) {
            dy = 1;
        }
        if (x + dx > (getWidth() - 30)) {
            dx = -1;
        }
        if (y + dy > (getHeight() - 30)) {
            dy = -1;
        }
        x = x + dx;
        y = y + dy;
    }
    public void paint(Graphics2D g) {
        g.fillOval(x, y, 30, 30);
    }
} 

编辑:解决问题,我根本没有告诉getwidth()和getheight()要参考什么。显然,如果我不告诉他们要得到什么,他们将返回null。derp。简单的修复是将它们更改为game.getWidth()和game.getheight()。不过,感谢您的帮助!您的所有投入也在其他领域也有帮助。:)

  1. Graphics/Java2D默认情况下,永远不要让合理的 Dimension,结果为零 Dimension,您必须覆盖getPreferredSize的CC_8,然后getWidth/Height将返回jpanels大小的正确坐标。

  2. 然后使用JFrame.pack()而不是任何尺寸。

  3. Swing JComponents覆盖paintComponent,而不是paint(),内部paintComponent 1st。代码线应为super.paintComponent,否则绘画累积。

  4. 切勿在Swing中使用Thread.sleep(int),也不要在Java7中使用自定义绘画或动画,然后使用Swing Timer代替Thread.sleep(int)停止的无尽环路。

这是某些设计决策变得更糟的复杂问题。

通常,Swing希望在约束管理器中使用组件。布局经理需要一定数量的信息,以便决定如何最好地布局这些组件。这包括getPreferred/Minimum/Maximum大小。

您遇到的问题是您实际上不想使用布局经理,因为您想手动定位Ball。当您抛出布局管理器时,您将对很多工作负责,以确保组件在父容器中正确和位置。

一个简单的解决方案是生成一个"游戏"表面,您可以在该表面上绘制游戏元素或实体。

问题是,您似乎不知道要使用哪种方法。您的BallJPanel延伸,但是您的Main面板本身正在绘画...这不是应该渲染组件的方式。

您可以简单地将Main用作主要的游戏表面,而不是将组件用作游戏实体的基础,而是引入了许多问题和管理开销,而是直接将所有实体呈现为主要游戏表面。这为您提供了更大的控制并简化了过程-IMHO

例如...

import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
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 Main extends JPanel {
    public static final int GAME_SPEED = 40;
    Ball ball = new Ball();
    protected void move() {
        ball.move(this);
    }
    public Main() {
        setLayout(null);
        Timer timer = new Timer(GAME_SPEED, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                move();
                repaint();
            }
        });
        timer.start();
    }
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g); 
        ball.paint((Graphics2D)g);
    }
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(400, 400);
    }
    public static void main(String args[]) throws InterruptedException {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }
                JFrame frame = new JFrame("Pong");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                Main game = new Main();
                frame.add(game);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            }
        });
    }
    public interface Entity {
        public void paint(Graphics2D g2d);
        public Rectangle getBounds();
    }
    public interface MovableEntity extends Entity {
        public void move(Container parent);
    }
    public class Ball implements MovableEntity {
        private int dx = 1;
        private int dy = 1;
        private int x;
        private int y;
        @Override
        public void move(Container parent) {
            int width = parent.getWidth();
            int height = parent.getHeight();
            int x = getX();
            int y = getY();
            x += dx;
            y += dy;
            if (x + dx < 0) {
                dx = 1;
            }
            if (y + dy < 0) {
                dy = 1;
            }
            if (x + dx > (width - getBounds().width)) {
                dx = -1;
            }
            if (y + dy > (height - getBounds().height)) {
                dy = -1;
            }
            setLocation(x, y);
        }
        @Override
        public void paint(Graphics2D g2d) {
            int width = getBounds().width;
            int height = getBounds().height;
            int dim = Math.min(width, height);
            int xPos = x + ((width - dim) / 2);
            int yPos = y + ((height - dim) / 2);
            g2d.fillOval(xPos, yPos, dim, dim);
        }
        @Override
        public Rectangle getBounds() {
            return new Rectangle(x, y, 30, 30);
        }
    }
}

最新更新