java 按下按钮时背景消失[关闭]

zxlwwiss  于 2022-12-25  发布在  Java
关注(0)|答案(1)|浏览(94)

编辑问题以包含desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将有助于其他人回答问题。
昨天关门了。
Improve this question
我已经使用Swing UI在Java中设置了一个游戏。

预期

当在屏幕上发射炮弹时,我希望背景一直在那里

问题

当我运行代码时,背景看起来很好。但是当发射抛射体的按钮被按下时,背景就消失了。

代码

public class ProjectileShooterTest {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI();
            }
        });
    }

    private static void createAndShowGUI() {
        JFrame f = new JFrame() {
        };

        ImageIcon background=new ImageIcon("Background.png");
        Image img=background.getImage();
        Image temp=img.getScaledInstance(800,440,Image.SCALE_SMOOTH);
        background=new ImageIcon(temp);

        JLabel back=new JLabel(background);
        back.setBounds(0,0,800,500);

        f.getContentPane().setLayout(new BorderLayout());
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(800,500);

        final ProjectileShooter projectileShooter = new ProjectileShooter();
        ProjectileShooterPanel projectileShooterPanel = new ProjectileShooterPanel(projectileShooter);
        projectileShooter.setPaintingComponent(projectileShooterPanel);

        JPanel controlPanel = new JPanel(new GridLayout(1,0));
        controlPanel.add(new JLabel("     Post-Launch Angle"));

        final JSlider angleSlider = new JSlider(70, 89, 85);
        angleSlider.setLayout( new FlowLayout() );

        controlPanel.add(angleSlider);
        f.add(back);

        controlPanel.add(new JLabel("                         Thrust"));
        final JSlider powerSlider = new JSlider(50, 80, 60);
        powerSlider.setLayout( new FlowLayout() );
        controlPanel.add(powerSlider);

        JButton shootButton = new JButton("Launch");
        shootButton.setLayout( new FlowLayout() );
        shootButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int angleDeg = angleSlider.getValue();
                int power = powerSlider.getValue();
                projectileShooter.setAngle(Math.toRadians(angleDeg));
                projectileShooter.setPower(power);
                projectileShooter.shoot();
            }
        });
        f.add(back);
        controlPanel.add(shootButton);

        f.getContentPane().add(controlPanel, BorderLayout.NORTH);
        f.getContentPane().add(projectileShooterPanel, BorderLayout.CENTER);
        f.setVisible(true);
        f.setLayout(new BorderLayout());
    }
}

class ProjectileShooter
{
    private double angleRad = Math.toRadians(45);
    private double power = 50;
    private Projectile projectile;
    private JComponent paintingComponent;

    void setPaintingComponent(JComponent paintingComponent)
    {
        this.paintingComponent = paintingComponent;
    }

    void setAngle(double angleRad)
    {
        this.angleRad = angleRad;
    }

    void setPower(double power)
    {
        this.power = power;
    }

    void shoot()
    {
        Thread t = new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                executeShot();
            }
        });
        t.setDaemon(true);
        t.start();
    }

    private void executeShot()
    {
        if (projectile != null)
        {
            return;
        }
        projectile = new Projectile();

        Point2D velocity =
                AffineTransform.getRotateInstance(angleRad).
                        transform(new Point2D.Double(1,0), null);
        velocity.setLocation(
                velocity.getX() * power * 0.5,
                velocity.getY() * power * 0.5);
        projectile.setVelocity(velocity);
        //System.out.println("Initial "+velocity);

        long prevTime = System.nanoTime();
        while (projectile.getPosition().getY() >= 0)
        {
            long currentTime = System.nanoTime();
            double dt = 3 * (currentTime - prevTime) / 1e8;
            projectile.performTimeStep(dt);

            prevTime = currentTime;
            paintingComponent.repaint();
            try
            {
                Thread.sleep(10);
            }
            catch (InterruptedException e)
            {
                Thread.currentThread().interrupt();
                return;
            }
        }

        projectile = null;
        paintingComponent.repaint();
    }

    Projectile getProjectile()
    {
        return projectile;
    }

}

问题

我该如何解决这个问题?

xdnvmnnf

xdnvmnnf1#

f.add(back);

相当于:

f.getContentPane().add(back, BorderLayout.CENTER);

在后面的代码中,您可以:

f.getContentPane().add(projectileShooterPanel, BorderLayout.CENTER);

这将导致问题,因为您无法将两个组件添加到CENTER。
Swing GUI是父/子设计,因此您需要类似以下内容:

f.getContentPane().add(back, BorderLayout.CENTER);
back.setLayout(new BorderLayout());
back.add(projectileShooterPanel, BorderLayout.CENTER);

我将让您弄清楚上述语句的逻辑顺序和位置。
另外,您为什么要:

f.setLayout(new BorderLayout());

在构造函数的末尾?这将替换原始布局的所有约束信息。
最后,你的射弹射击面板需要是透明的,否则它会覆盖背景。所以你还需要:

projectileShooterPanel.setOpaque( false );

注意:如果不使用JLabel作为背景,在投射型射手面板中绘制背景会更容易。这样,您就不会遇到尝试将多个面板添加到另一个面板的问题,射手面板也不需要透明。
编辑:
您需要在组件之间建立父/子关系,例如:

- frame
    - content pane
        - background image 
            - projectile panel
                - projectile

我的第一个建议是将背景作为一个组件,并向其中添加投射面板:
1.设置背景组件的布局
1.添加投射物面板到背景
1.使投射物面板透明,以便您可以看到图像
这不是最佳解决方案
第二种解决方案是将背景绘制为射弹面板的一部分:
1.在投射体面板中绘制背景图像
1.给炮弹上色
这是首选解决方案。

相关问题