Java Swing - 除非在构造函数中,否则组件不可见?

问题描述 投票:0回答:1

我正在使用 Swing 在 Java 中制作 Brick Breaker 类型的游戏,但我的 J组件都不可见,除非它们是在构造函数中创建的。另一个奇怪的注意事项是,只有在将当前组件添加到面板后立即运行

setVisible()
时,我当前的组件才可见。我怎样才能稍后通过方法添加它们(例如在
startGame()
内)?

Main.java

public class Main {
    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                BrickBreaker gameInstance = new BrickBreaker();
                gameInstance.startGame();
            }
        });
    }
}

BrickBreaker.java

import java.awt.BorderLayout;
import java.awt.Color;
import java.net.URL;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class BrickBreaker {

    boolean gameOver = false;
    int frameBoundX = 500;
    int frameBoundY = 600;
    JFrame frame;
    JPanel panel;
    Ball ball;
    Slider slider;
    ArrayList<Brick> brickList = new ArrayList<Brick>();

    public BrickBreaker() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(frameBoundX, frameBoundY);
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);

        // Add new panel
        panel = new JPanel(new BorderLayout());
        frame.setContentPane(panel);

        // Add slider
        slider = new Slider(200, frameBoundY - 100, 100, 30);
        panel.add(slider);
        frame.setVisible(true);

        // Add ball
        ball = new Ball(this, frameBoundX, frameBoundY);
        panel.add(ball);
        frame.setVisible(true);

        // Add Bricks
        generateBricks();
        for (Brick brick : brickList) {
            panel.add(brick);
            frame.setVisible(true);
        }

        // Add background
        URL backgroundUrl = BrickBreaker.class.getResource("background.jpg");
        ImageIcon backgroundIcon = new ImageIcon(backgroundUrl);
        JLabel backgroundLabel = new JLabel(backgroundIcon);
        backgroundLabel.setBounds(0, 0, backgroundIcon.getIconWidth(),
                backgroundIcon.getIconHeight());
        panel.add(backgroundLabel);
        frame.setVisible(true);
    }

    public void startGame() {
        // Add ball
        // ball = new Ball(this, frameBoundX, frameBoundY);
        // panel.add(ball);
        // setVisible(true);
        // panel.repaint();
        // panel.revalidate();

        slider.start();
        ball.start();
    }

    public void endGame() {
        System.out.println("GAME OVER");
        // JLabel endSign = new JLabel("MY TEXT HERE");
        // endSign.setText("GAME OVER");
        // endSign.setBounds(frameBoundX/2, frameBoundY/2, 200, 200);
        // endSign.setForeground(Color.white);
        // endSign.setVisible(true);
        // panel.add(endSign);
        // panel.setVisible(true);
        // // Repaint the panel
        // panel.revalidate();
        // panel.repaint();
        slider.end();
    }

    public boolean isGameOver() {
        return gameOver;
    }

    public void generateBricks() {
        // Unique starting and iterating numbers are due to the window size
        // while also spacing out the bricks evenly
        for (int row = 10; row <= 85; row += 35) {
            for (int b = 5; b < frameBoundX; b += 99) {
                System.out.println("Generating brick #" + b);
                Brick brick = new Brick(b, row);
                brickList.add(brick);
            }
        }
    }
}

Brick.java(查看组件是如何实现的)

import javax.swing.JComponent;
import java.awt.Rectangle;
import java.awt.Color;
import java.awt.Graphics;

public class Brick extends JComponent {

    private int x;
    private int y;
    private int width = 94;
    private int height = 30;
    private int health = 1;

    public Brick(int startingX, int startingY) {
        this.x = startingX;
        this.y = startingY;
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.MAGENTA);
        g.fillRect(x, y, width, height);
        g.dispose();
    }

    public Rectangle getBounds() {
        return new Rectangle(x, y, width, height);
    }

    public int reduceHealth(){
        this.health--;
        if (this.health < 1){
            System.out.println("Brick has zero health! Disappearing!");
            setVisible(false);
        }
        return this.health;
    }

}

如果我尝试在构造函数之外的其他任何地方声明滑块、球或砖块,它们将不会出现在屏幕上。最初,我还通过调用

invokeLater()
使用 EDT 获得了 Main java 文件,但我删除了这种想法,认为这可能是一个问题,但它仍然在发生。

java swing jpanel jcomponent
1个回答
0
投票

“...除非在构造函数中创建,否则我的 JComponent 都不可见。...仅当我将其添加到面板后立即运行

setVisible()
时才可见。以后如何通过以下方式添加它们方法(例如在
startGame()
内)?...”

数据模块化。
为每个任务创建一个方法

我建议封装GUI相关数据。
此外,由于 Ball 正在访问 thisframeBoundXframeBoundY,因此只需将 nest 放在该类中即可。

这是一个例子。

class BrickBreaker {

    GUI gui;
    boolean gameOver = false;

    static class GUI extends JFrame {
        int frameBoundX, frameBoundY;
        JPanel panel;
        Ball ball;
        Slider slider;
        ArrayList<Brick> brickList;

        GUI() {
            initialize();
            // Add new panel
            add(panel);
            // Add slider
            panel.add(slider);
            // Add ball
            panel.add(ball);
            // Add Bricks
            for (Brick b : brickList) panel.add(b);
            // Add background
            URL backgroundUrl = BrickBreaker.class.getResource("background.jpg");
            ImageIcon backgroundIcon = new ImageIcon(backgroundUrl);
            JLabel backgroundLabel = new JLabel(backgroundIcon);
            backgroundLabel.setBounds(0, 0, backgroundIcon.getIconWidth(),
                backgroundIcon.getIconHeight());
            panel.add(backgroundLabel);
            panel.setVisible(true);
            setVisible(true);
            setDefaultCloseOperation(EXIT_ON_CLOSE);
            setSize(frameBoundX, frameBoundY);
            setLocationRelativeTo(null);
            setResizable(false);
        }

        void initialize() {
            frameBoundX = 500;
            frameBoundY = 600;
            panel = new JPanel(new BorderLayout());
            ball = new Ball();
            slider = new Slider(200, frameBoundY - 100, 100, 30);
            generateBricks();
        }

        public void generateBricks() { ... }

        private class Ball extends JComponent {
        }

        private class Slider extends JComponent {
            public Slider(int x, int y, int w, int h) {
            }
        }
    }

    public void startGame() { ... }

    public void endGame() { ... }

    public boolean isGameOver() { ... }
}
SwingUtilities.invokeLater(() -> {
    BrickBreaker gameInstance = new BrickBreaker();
    gameInstance.gui = new BrickBreaker.GUI();
    gameInstance.startGame();
    while (!gameInstance.isGameOver()) {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    gameInstance.endGame();
});
© www.soinside.com 2019 - 2024. All rights reserved.