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

Swing JLayeredPane not painting all elements on paintAll call

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

paintAllToImage 方法中单击按钮,我创建 BufferedImage 并使用 component.paintAll(image.getGraphics()); 在该图像上绘制 JLayerePane
问题是,该图像具有仅 Canvas 涂漆(完全用黄色填充)。请参阅所附图片。

(按钮上面的部分是实际绘制的,按钮下面的部分是图像,从 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;
    }
}

编辑:新答案

通过调整此 Stack Overflow answer,似乎可以将轻量级 CustomPanel 置于重量级 Panel 中,并将其置于另一个重量级 Panel 之上。这是屏幕截图:

程序如下:

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

/**
 * Adapted from 
 */
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);
        }
    }
}

旧答案

使用 MadProgrammer to avoid the Canvas class, you could use two instances of your CustomPanel class. This class extends the Swing based lightweight JPanel instead of the heavyweight AWT based Canvas. See 的建议获取有关轻量级与重量级 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;
    }
}