堆叠的 JPanel 重绘不正确

stacked JPanel repaint not correctly

我试着用 2 个面板互相堆叠来制作游戏,第一个面板用于 canvas,其中所有图块和所有游戏对象都在上面绘制,第二个面板用于我拥有的顶层框架具有透明背景的 png 图像,将包含 JTextBoxJTabbedPanelJLabel

我的问题是当我重新粉刷 canvas 时,顶部框架的一部分被 canvas 覆盖。

这是为什么?而且当我在 canvas 上添加 JButton 时,JButton 绘制在我的顶部框架面板的顶部。

编辑:

我试过使用 JLayeredPane,但仍然得到相同的结果。

    // initComponent from MyGame
    private void initComponent() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("My Game");
        this.setSize(320, 240);
        this.setLayout(null);
        this.setUndecorated(true);
        this.setResizable(false);

        JLayeredPane layered = this.getLayeredPane();
        layered.add(new Canvas(), 0);
        layered.add(new TopFrame(), 1);
    }

这个顶框和我的 canvas:

我得到了什么 |我想要什么

主要

@SuppressWarnings("serial")
public class MyGame extends JFrame {

    public MyGame() {
        this.initComponent();
    }

    private void initComponent() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("My Game");
        this.setSize(320, 240);
        this.setLayout(null);
        this.setUndecorated(true);
        this.setResizable(false);

        this.add(new TopFrame());       
        this.add(new Canvas());
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame game = new MyGame();
                game.setVisible(true);
            }
        });
    }
}

TopFrame

@SuppressWarnings("serial")
public class TopFrame extends JPanel {
    private static final int FRAME_WIDTH = 320;
    private static final int FRAME_HEIGHT = 240;

    private BufferedImage bgImage;

    public TopFrame() {
        this.initComponent();
    }

    private void initComponent() {
        this.setLayout(null);
        this.setBounds(0, 0, FRAME_WIDTH, FRAME_HEIGHT);

        bgImage = new BufferedImage(FRAME_WIDTH, FRAME_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR_PRE);
        try {
            bgImage = ImageIO.read(new File("FRAME.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(bgImage, 0, 0, this);
    }
}

Canvas

@SuppressWarnings("serial")
public class Canvas extends JPanel {
    private static final int CANVAS_WIDTH = 227;
    private static final int CANVAS_HEIGHT = 240;

    BufferedImage image;
    BufferedImage imgBuffer;
    Graphics2D g2d;

    public Canvas() {
        this.initComponent();
    }

    private void initComponent() {
        Timer timer = new Timer();

        this.setBounds(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
        imgBuffer = new BufferedImage(CANVAS_WIDTH, CANVAS_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR_PRE);
        g2d = imgBuffer.createGraphics();

        try {
            image = ImageIO.read(new File("tile.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        timer.schedule(new TimerTask(){
            @Override
            public void run() {
                drawComponent();
                repaint();
            }
        }, 0, 100);
    }

    public void drawComponent() {
        /* will do tile drawing */
        g2d.drawImage(image, 0, 0, this);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(imgBuffer, 0, 0, this);
    }
}

是否可以让我的 canvas 在底部绘制所有包含的对象?

[已解决] 使用 JLayeredPane 并制作 TopFrame setOpaque(false);

我在尝试使用 JLayeredPane 时遇到错误代码。

我现在的最终代码工作代码:

主要

@SuppressWarnings("serial")
public class MyGame extends JFrame {

    public MyGame() {
        this.initComponent();
    }

    private void initComponent() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setTitle("My Game");
        this.setSize(320, 240);
        this.setLayout(null);
        this.setUndecorated(true);
        this.setResizable(false);

        JLayeredPane layered = this.getLayeredPane();
        layered.add(new Canvas(), new Integer(0));
        layered.add(new TopFrame(), new Integer(1));
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame game = new MyGame();
                game.setVisible(true);
            }
        });
    }
}

TopFrame

@SuppressWarnings("serial")
public class TopFrame extends JPanel {
    private static final int FRAME_WIDTH = 320;
    private static final int FRAME_HEIGHT = 240;

    private BufferedImage bgImage;

    public TopFrame() {
        this.initComponent();
    }

    private void initComponent() {
        this.setLayout(null);
        this.setBounds(0, 0, FRAME_WIDTH, FRAME_HEIGHT);
        this.setOpaque(false);

        bgImage = new BufferedImage(FRAME_WIDTH, FRAME_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR_PRE);
        try {
            bgImage = ImageIO.read(new File("FRAME.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void paintComponent(Graphics g) {
        // super.paintComponent(g);
        g.drawImage(bgImage, 0, 0, this);
    }
}

Canvas

@SuppressWarnings("serial")
public class Canvas extends JPanel {
    private static final int CANVAS_WIDTH = 227;
    private static final int CANVAS_HEIGHT = 240;

    BufferedImage image;
    BufferedImage imgBuffer;
    Graphics2D g2d;

    public Canvas() {
        this.initComponent();
    }

    private void initComponent() {
        Timer timer = new Timer();

        this.setBounds(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
        imgBuffer = new BufferedImage(CANVAS_WIDTH, CANVAS_HEIGHT, BufferedImage.TYPE_4BYTE_ABGR_PRE);
        g2d = imgBuffer.createGraphics();

        try {
            image = ImageIO.read(new File("tile.png"));
        } catch (IOException e) {
            e.printStackTrace();
        }

        timer.schedule(new TimerTask(){
            @Override
            public void run() {
                drawComponent();
                repaint();
            }
        }, 0, 100);
    }

    public void drawComponent() {
        /* will do tile drawing */
        g2d.drawImage(image, 0, 0, this);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(imgBuffer, 0, 0, this);
    }
}