You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Swing游戏点击发射按钮后背景消失的解决方案咨询

解决Java Swing发射抛射物后背景消失的问题

问题现象

  • 程序初始运行时,背景图片显示正常
  • 点击「Launch」按钮发射抛射物后,背景图片消失

问题原因

  1. 组件层级与布局冲突:代码中重复调用f.add(back)添加背景Label,后续又将controlPanel和projectileShooterPanel添加到JFrame的BorderLayout区域,这些组件会直接覆盖在背景Label之上,导致背景被遮挡。
  2. 面板不透明特性:默认情况下Swing组件的opaque属性为true,projectileShooterPanel作为CENTER区域的组件会完全填充该区域,且如果它的paintComponent方法没有绘制背景,就会覆盖掉底层的背景图片。

解决方案

推荐方案:将背景整合到抛射物面板中

把背景图片的绘制逻辑放到负责渲染抛射物的ProjectileShooterPanel里,让背景和抛射物处于同一绘制层级,从根源避免覆盖问题。

步骤1:修改GUI初始化代码

移除多余的背景Label添加逻辑,将背景图片传递给ProjectileShooterPanel,同时设置控制面板为透明:

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

    // 加载并缩放背景图片
    ImageIcon backgroundIcon = new ImageIcon("Background.png");
    Image img = backgroundIcon.getImage();
    Image scaledBackground = img.getScaledInstance(800, 440, Image.SCALE_SMOOTH);

    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, scaledBackground);
    projectileShooter.setPaintingComponent(projectileShooterPanel);

    JPanel controlPanel = new JPanel(new GridLayout(1, 0));
    controlPanel.setOpaque(false); // 设为透明,避免遮挡背景
    controlPanel.add(new JLabel("     Post-Launch Angle"));

    final JSlider angleSlider = new JSlider(70, 89, 85);
    controlPanel.add(angleSlider);

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

    JButton shootButton = new JButton("Launch");
    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();
        }
    });
    controlPanel.add(shootButton);

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

步骤2:完善ProjectileShooterPanel类

在面板的paintComponent方法中,先绘制背景再绘制抛射物:

class ProjectileShooterPanel extends JPanel {
    private ProjectileShooter shooter;
    private Image background;

    public ProjectileShooterPanel(ProjectileShooter shooter, Image background) {
        this.shooter = shooter;
        this.background = background;
        setOpaque(false); // 确保面板不遮挡底层内容
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 优先绘制背景图片
        if (background != null) {
            g.drawImage(background, 0, 0, getWidth(), getHeight(), this);
        }
        // 绘制抛射物
        Projectile projectile = shooter.getProjectile();
        if (projectile != null) {
            Point2D pos = projectile.getPosition();
            // 注意Swing坐标系Y轴向下,需转换坐标
            int drawX = (int) pos.getX() - 5;
            int drawY = (int) (getHeight() - pos.getY()) - 5;
            g.setColor(Color.RED);
            g.fillOval(drawX, drawY, 10, 10);
        }
    }
}

备选方案:调整组件透明度与层级

如果不想修改抛射物面板的绘制逻辑,可通过以下方式修复:

  • 只调用一次f.add(back),并确保它是第一个被添加到JFrame的组件
  • 设置controlPanel和projectileShooterPanel的setOpaque(false),让底层背景能透出来
  • 注意:该方案可能因布局管理器的特性出现显示异常,不如推荐方案稳定

额外注意事项

  • 移除代码中重复的f.add(back)调用,避免布局混乱
  • 确保Projectile类的getPosition()返回的坐标逻辑正确,适配Swing的坐标系(Y轴向下)
  • repaint()方法是线程安全的,当前抛射物线程中的调用无需修改

内容的提问来源于stack exchange,提问作者user20823464

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 00:10:20