Java Swing JLayeredPane未在paintAll调用上绘制所有元素

Java Swing JLayeredPane未在paintAll调用上绘制所有元素,java,swing,canvas,awt,jlayeredpane,Java,Swing,Canvas,Awt,Jlayeredpane,我有JLayeredPane在0级上包含Canvas(在Paint方法中填充自己的黄色)和在1级上包含JPanel(在构造函数中将其it背景设置为红色) 在按钮上单击paintAllToImage方法I创建BufferedImage并使用component.paintAll(image.getGraphics())在此图像上绘制JLayerePane问题是,该图像只绘制了画布(完全用黄色填充)。请看图片附件 (按钮上方的部分是实际绘制的,按钮下方的部分是图像,由JLayeredPane创建)

我有
JLayeredPane
在0级上包含
Canvas
(在
Paint
方法中填充自己的黄色)和在1级上包含
JPanel
(在构造函数中将其it背景设置为红色)

在按钮上单击
paintAllToImage
方法I创建
BufferedImage
并使用
component.paintAll(image.getGraphics())在此图像上绘制
JLayerePane

问题是,该图像只绘制了
画布
(完全用黄色填充)。请看图片附件

(按钮上方的部分是实际绘制的,按钮下方的部分是图像,由
JLayeredPane
创建)

以下是完整的代码:

public class LayeredPaneEx extends JPanel {

    private JLayeredPane layeredPane;
    public LayeredPaneEx()    {
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));

        layeredPane = new JLayeredPane();
        layeredPane.setPreferredSize(new Dimension(300, 310));
        layeredPane.setLayout(null);

        Canvas panel = new CustomCanvas();
        panel.setSize(300, 400);
        CustomPanel customPanel = new CustomPanel();
        layeredPane.add(panel, new Integer(0));
        layeredPane.add(customPanel, new Integer(1));

        add(layeredPane);

        JButton paintBtn = new JButton("Paint All");
        paintBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ImageIcon icon = new ImageIcon(paintAllToImage(layeredPane));
                JLabel imageLabel = new JLabel(icon);
                add(imageLabel);
            }
        });
        add(paintBtn);

        JLabel paintLabel = new JLabel();
        paintLabel.setPreferredSize(new Dimension(300, 300));
    }

    private class CustomCanvas extends Canvas  {
        @Override
        public void paint(Graphics g) {
            g.setColor(Color.YELLOW);
            g.fillRect(0, 0, getWidth(), getHeight());
        }
    }

    private class CustomPanel extends JPanel {
        CustomPanel() {
            setSize(100, 100);
            setBackground(Color.RED);
        }
    }

    private static void createAndShowGUI() {
        JFrame frame = new JFrame("LayeredPaneDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JComponent newContentPane = new LayeredPaneEx();
        newContentPane.setOpaque(true);
        frame.setContentPane(newContentPane);

        frame.pack();
        frame.setVisible(true);
    }

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

    public static BufferedImage paintAllToImage(Component component) {
        BufferedImage image;
        image = new BufferedImage(
                component.getWidth(),
                component.getHeight(),
                BufferedImage.TYPE_INT_RGB
        );
        component.paintAll(image.getGraphics());
        return image;
    }
}

编辑:新答案

通过调整这一点,似乎可以将一个轻量级
CustomPanel
放在一个重量级
面板中,并将其放在另一个重量级
面板上。以下是一个屏幕截图:

以下是节目:

import java.awt.*;
import javax.swing.*;

/**
 * Adapted from https://stackoverflow.com/a/1428298/1694043.
 */
public class GuiTest {
    public static void main(String[] arguments) {
        new GuiTest();
    }

    public GuiTest() {
        JFrame frame = new JFrame("Heavyweight versus lightweight");
        frame.setSize(500, 500);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        addPanelsToFrame(frame);

        SwingUtilities.invokeLater(() -> frame.setVisible(true));
    }

    private void addPanelsToFrame(JFrame frame) {
        CustomCanvas customCanvas = new CustomCanvas(300, 400, Color.YELLOW);
        Panel awtPanel1 = new Panel(new BorderLayout());
        awtPanel1.setSize(300, 400);
        awtPanel1.add(customCanvas, BorderLayout.CENTER);
        frame.getLayeredPane().add(awtPanel1, JLayeredPane.DEFAULT_LAYER);

        CustomPanel customPanel = new CustomPanel(100, 100, Color.RED);
        Panel awtPanel2 = new Panel(new BorderLayout());
        awtPanel2.setSize(100, 100);
        awtPanel2.add(customPanel, BorderLayout.CENTER);
        frame.getLayeredPane().add(awtPanel2, JLayeredPane.PALETTE_LAYER);
    }


    private class CustomCanvas extends Canvas {
        private Color backgroundColor;

        public CustomCanvas(int width, int height, Color backgroundColor) {
            setSize(width, height);
            this.backgroundColor = backgroundColor;
        }

        @Override
        public void paint(Graphics g) {
            g.setColor(backgroundColor);
            g.fillRect(0, 0, getWidth(), getHeight());
        }
    }


    private class CustomPanel extends JPanel {
        public CustomPanel(int width, int height, Color backgroundColor) {
            setSize(width, height);
            setBackground(backgroundColor);
        }
    }
}

旧答案

为了避免使用
Canvas
类,您可以使用
CustomPanel
类的两个实例。此类扩展了基于Swing的轻量级
JPanel
,而不是基于重量级AWT的
画布。有关轻量级与重量级Java GUI组件的更多信息,请参阅

以下是一个屏幕截图:

以下是修改后的代码:

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;

public class LayeredPaneEx extends JPanel {
    private JLayeredPane layeredPane;

    public LayeredPaneEx()    {
        setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));

        layeredPane = new JLayeredPane();
        layeredPane.setPreferredSize(new Dimension(300, 310));
        layeredPane.setLayout(null);

        //Canvas panel = new CustomCanvas();
        //panel.setSize(300, 400);
        //CustomPanel customPanel = new CustomPanel();
        //layeredPane.add(panel, new Integer(0));
        //layeredPane.add(customPanel, new Integer(1));
        layeredPane.add(new CustomPanel(300, 400, Color.YELLOW), new Integer(0));
        layeredPane.add(new CustomPanel(100, 100, Color.RED), new Integer(1));

        add(layeredPane);

        JButton paintBtn = new JButton("Paint All");
        paintBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                ImageIcon icon = new ImageIcon(paintAllToImage(layeredPane));
                JLabel imageLabel = new JLabel(icon);
                add(imageLabel);
            }
        });
        add(paintBtn);

        JLabel paintLabel = new JLabel();
        paintLabel.setPreferredSize(new Dimension(300, 300));
    }

//    private class CustomCanvas extends Canvas  {
//        @Override
//        public void paint(Graphics g) {
//            g.setColor(Color.YELLOW);
//            g.fillRect(0, 0, getWidth(), getHeight());
//        }
//    }

    private class CustomPanel extends JPanel {
        public CustomPanel(int width, int height, Color backgroundColor) {
            setSize(width, height);
            setBackground(backgroundColor);
        }
    }

    private static void createAndShowGUI() {
        JFrame frame = new JFrame("LayeredPaneDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JComponent newContentPane = new LayeredPaneEx();
        newContentPane.setOpaque(true);
        frame.setContentPane(newContentPane);

        frame.pack();
        frame.setVisible(true);
    }

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

    public BufferedImage paintAllToImage(Component component) {
        BufferedImage image = new BufferedImage(
                component.getWidth(),
                component.getHeight(),
                BufferedImage.TYPE_INT_RGB
        );
        component.paintAll(image.getGraphics());

        return image;
    }
}

当心将重量级(
Canvas
)与轻量级组件混合在一起。因为AWT组件没有z顺序的概念,所以您会发现这将导致无休止的问题。此外,您应该更喜欢
printAll
而不是
paintAll
谢谢,这肯定会奏效,但如果我必须在画布上绘制我的JPanel呢?正如Oracle文章“混合了重量级和轻量级组件”所说,Java8(我正在使用的)应该没有问题。虽然在这种情况下,画布是在JPanel上绘制的。我的建议是使用两个轻量级面板。那么,哪个面板在顶部就不重要了。在我看来,没有理由在这个程序中使用重量级组件。如果你想画画,你可以覆盖面板的
paintComponent
方法。这是一个关于Swing中自定义绘制的很好的教程:。遗憾的是,这个程序只是RealTask的一个沙盒版本,在一个
容器中有重叠的
Canvas
JPanel
。我知道,你有一个遗留问题。用
JPanel
替换
Canvas
组件有多困难?