简体   繁体   English

JFrame getHeight()和getWidth()返回0

[英]JFrame getHeight() and getWidth() return 0

I'm making a simple pong game; 我正在做一个简单的乒乓球比赛; and part of the collision mechanics require getting the width and height of the canvas to redirect the ball. 并且部分碰撞力学需要获得画布的宽度和高度以重定向球。 However, getWidth() and getHeight() return 0 for some reason. 但是, getWidth()getHeight()由于某种原因返回0。 Here's the main block of code. 这是主要的代码块。

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);
        }
    }
}

And here's the actual Ball class, which handles movement conditions. 这是实际的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);
    }
} 

EDIT: Problem solved, I simply didn't tell getWidth() and getHeight() what to refer to. 编辑:问题解决了,我只是没有告诉getWidth()和getHeight()引用什么。 Obviously, if I don't tell them what to get, they'll return null. 显然,如果我不告诉他们要得到什么,他们将返回null。 Derp. DERP。 The simple fix was to change them to game.getWidth() and game.getHeight(). 简单的解决方法是将它们更改为game.getWidth()和game.getHeight()。 Thanks for the help, though! 谢谢你的帮助! All your inputs help in other areas as well. 您的所有输入也有助于其他领域。 :) :)

  1. Graphics / Java2D by default never returs reasonable Dimension , result is zero Dimension , you have to override getPreferredSize for JPanel , then getWidth/Height will return correct coordinates for JPanels' size. 默认情况下, Graphics / Java2D永远不会返回合理的Dimension ,结果为零Dimension ,您必须为JPanel覆盖getPreferredSize ,然后getWidth/Height将返回JPanels大小的正确坐标。

  2. then to use JFrame.pack() instead of any sizing. 然后使用JFrame.pack()而不是任何大小调整。

  3. override paintComponent for Swing JComponents , instead of paint() , inside paintComponent 1st. paintComponent 1st中覆盖Swing JComponents paintComponent ,而不是paint() code line should be super.paintComponent , otherwise painting cumulated. 代码行应该是super.paintComponent ,否则绘制累积。

  4. never to use Thread.sleep(int) in Swing , nor for Custom painting or animations in Java7 and Swing, use Swing Timer instead endless loop stopped by Thread.sleep(int) . 永远不要在Swing使用Thread.sleep(int) ,也不要在Java7和Swing中使用自定义绘制或动画,而是使用Swing Timer而不是Thread.sleep(int)停止的无限循环。

This is a complex issue made worse by some design decisions. 这是一个复杂的问题,由于某些设计决策而变得更糟。

Normally, Swing wants components to be used within the constraints a layout manager. 通常,Swing希望组件在布局管理器的约束内使用。 Layout managers require a certain amount of information in order to make decisions about how best layout these components. 布局管理器需要一定量的信息才能决定如何最好地布局这些组件。 This includes getPreferred/Minimum/Maximum size. 这包括getPreferred/Minimum/Maximum大小。

The problem you have is you don't actually want to use layout managers, as you want to position the Ball manually. 您遇到的问题是您实际上并不想使用布局管理器,因为您想手动定位Ball When you throw out the layout manager, you become responsible for a lot of work, ensuring that the component is size and position correctly within the parent container. 当您抛弃布局管理器时,您将负责大量工作,确保组件在父容器中的大小和位置正确。

A simpler solution would be to generate a "game" surface onto which you can paint game elements or entities. 一个更简单的解决方案是生成一个“游戏”表面,您可以在其上绘制游戏元素或实体。

The problem is, you don't seem to know which approach you want to use. 问题是,您似乎不知道要使用哪种方法。 Your Ball extends from JPanel , but your Main panel is painting itself...this is not how components should be rendered. 你的BallJPanel扩展,但你的Main面板正在自己绘画......这不是组件应该如何渲染。

Instead of using components as a basis for game entities, which introduces numerous issues and management overhead, you could simply use Main as the primary gaming surface and render all the entities to it directly. 而不是使用组件作为游戏实体的基础,这会引入许多问题和管理开销,您可以简单地使用Main作为主要游戏界面并直接渲染所有实体。 This gives you greater control and simplifies the process - IMHO 这为您提供了更好的控制并简化了流程 - 恕我直言

For example... 例如...

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);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM