Java 自定义分层容器中的绘画问题?

Java 自定义分层容器中的绘画问题?,java,paint,layer,pane,Java,Paint,Layer,Pane,因此,我正在处理一个需要自定义类的项目。 它有两个成员“地面”和“前景”,分别是JPanel和一个背景(Image)成员 它应该显示的方式是,应该先画背景图像,然后在上面画出地面的所有组成部分,然后在顶点画出前景的组成部分。所以前景掩盖了地面,而地面掩盖了背景。背景只应显示在地面和前景中没有组件的地方,或者JPanels中有透明度的地方 其绘制功能如下所示: @Override public void paint(Graphics g){ g.drawImage(background, 0

因此,我正在处理一个需要自定义类的项目。 它有两个成员“地面”和“前景”,分别是
JPanel
和一个背景(
Image
)成员

它应该显示的方式是,应该先画背景图像,然后在上面画出地面的所有组成部分,然后在顶点画出前景的组成部分。所以前景掩盖了地面,而地面掩盖了背景。背景只应显示在地面和前景中没有
组件的地方,或者
JPanel
s中有透明度的地方

其绘制功能如下所示:

@Override
public void paint(Graphics g){
   g.drawImage(background, 0, 0, null);
   ground.paint(g.create());
   foreground.paint(g.create());
   g.dispose();
}
但这种情况不会发生。只绘制背景图像,不显示任何其他内容

我使用了
System.out.println()
函数来检查地面和前景是否确实容纳了组件,它们确实容纳了组件。但他们就是不表现出来


这里有人能帮我吗?

最重要的问题是您没有调用
super.paint
,这会阻止以前在
图形
上下文中绘制的内容被清除或任何子组件被绘制

要绘制背景,应使用用于绘制组件背景的
paintComponent

如果需要在子组件下绘制,但在背景上绘制,则仍应使用
paintComponent
,但首先绘制背景,然后绘制下一层。组件将在
paintComponent
之后进行喷漆

在组件上绘制实际上更复杂

仔细观察并

根据代码片段更新

在从
容器扩展而来的
屏幕
中,您正在执行

@Override
public void paint(Graphics g) {
    super.paint(g);
    GraphicsUtilities.drawPictureTiled(background, g);
    paintComponents(g);
    g.dispose();
}
  • 不要调用
    paintComponents
    super。paint
    已经这样做了
  • 不要在未创建的
    图形
    上下文上调用
    dispose
  • 基于我所拥有的示例代码的其余部分,您应该从
    JPanel
    扩展,并覆盖
    paintComponent
    。这将允许您放置在组件层下
因为
GroundPanel
ForeGroundPanel
都是
JPanel
s,所以没有必要自己绘制它们。事实上,您可以简单地使用
OverlayLayout
甚至是
GridBagLayout
将它们直接添加到
NestedScreen
中,NestedScreen本身就是一个容器

所以,我剥离了你的示例代码,这样我就可以用缺失的代码作为示例。我有点想像力,只是做了一个
JPanel
作为暂停屏幕

通过使用
GridBagLayout

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test1001 {

    public static void main(String[] args) {
        new Test1001();
    }

    public Test1001() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                try {
                    NestedScreen screen = new NestedScreen();
                    screen.setBackgroundLayer(ImageIO.read(getClass().getResource("/Sky.png")));

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(screen);
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                } catch (IOException exp) {
                    exp.printStackTrace();
                }
            }
        });
    }

    public interface GraphicsEngineComponents {

    }

    public class NestedScreen extends Screen implements GraphicsEngineComponents {

        GroundPanel ground;
        ForeGroundPanel foreground;
        private PausePane pausePane;

        public NestedScreen() {

            ground = new GroundPanel();
            foreground = new ForeGroundPanel();
            pausePane = new PausePane();

            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 1;
            gbc.weighty = 1;
            gbc.fill = GridBagConstraints.BOTH;

            add(pausePane, gbc);
            add(foreground, gbc);
            add(ground, gbc);

            MouseAdapter handler = new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    pausePane.setVisible(!pausePane.isVisible());
                }
            };

            addMouseListener(handler);
            foreground.addMouseListener(handler);
            ground.addMouseListener(handler);

        }

        public GroundPanel getGroundLayer() {
            return ground;
        }

        public ForeGroundPanel getForegroundLayer() {
            return foreground;
        }

        public void setBackgroundLayer(BufferedImage background) {
            super.setBackgroundLayer(background);
        }

        public class GroundPanel extends JPanel {

            public GroundPanel() {
                setOpaque(false);
            }

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(Color.GREEN);
                g.fillRect(0, getHeight() - 200, getWidth(), 200);
            }

        }

        public class PausePane extends JPanel {

            private JLabel label;

            public PausePane() {
                setVisible(false);
                setOpaque(false);
                setBackground(new Color(0, 0, 0, 128));
                setLayout(new GridBagLayout());

                label = new JLabel("Paused");
                label.setHorizontalAlignment(JLabel.CENTER);
                label.setVerticalAlignment(JLabel.CENTER);
                Font font = label.getFont();
                font = font.deriveFont(Font.BOLD, 48f);
                label.setFont(font);
                label.setForeground(Color.WHITE);
                add(label);
            }

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                g.setColor(getBackground());
                g.fillRect(0, 0, getWidth(), getHeight());
            }

        }

        public class ForeGroundPanel extends JPanel {

            private BufferedImage pony;

            public ForeGroundPanel() {
                setOpaque(false);
                try {
                    pony = ImageIO.read(getClass().getResource("/Pony.png"));
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }

            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (pony != null) {
                    int x = (getWidth() - pony.getWidth()) / 2;
                    int y = getHeight() - 200 - (pony.getHeight() / 2);
                    g.drawImage(pony, x, y, this);
                }
            }

        }
    }

    public class Screen extends JPanel implements GraphicsEngineComponents {

        private BufferedImage background;

        public Screen() {
        }

        @Override
        public String toString() {
            return "Screen{" + "background=" + background + '}';
        }

        public BufferedImage getBackgroundPicture() {
            return background;
        }

        @Override
        public Dimension getPreferredSize() {
            return background == null ? super.getPreferredSize() : new Dimension(background.getWidth(), background.getHeight());
        }

        protected void setBackgroundLayer(BufferedImage background) {
            if (background != null && background.getHeight() != 0 && background.getWidth() != 0) {
                this.background = background;
            }
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (background != null) {
                g.drawImage(background, 0, 0, this);
            }
        }
    }

}
看看并了解如何在秋千绘画作品


一个基本的想法是避免使用所有这些复合或嵌套组件,而是创建一个引擎,可以直接将层绘制到
图形
上下文上,甚至可以绘制到
缓冲图像
,您可以将其绘制到单个组件上……

有几种方法可以做到这一点。我只介绍一种方法

  • 创建一个背景面板,在其中绘制背景图像(在下面的示例中,它是
    BackgroundPanel
    ,图像仅为forresty背景)。将该面板设置为框架的内容窗格

  • 创建另一个接地面板,您也可以在其中绘制一些东西(在下面的示例中,如果它是
    接地面板
    ,只绘制了bugs bunny的图像)

  • 创建前景面板并将其添加到地面面板。您可以向其添加前景组件。(在下面的示例中,前景图像是青草山,我还向其添加了一个按钮。)

  • 所有面板的不透明属性都应设置为false,以允许其后面的面板以任何透明度显示


更新

当然,您可以始终使用
JLayeredPane
。这就是它的用途。请参见此示例

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;

public class LayeredPaneDemo {

    public static final int DIM_WIDTH = 600;
    public static final int DIM_HEIGHT = 400;

    public LayeredPaneDemo() {
        ContainerPanel container = new ContainerPanel();
        JLabel title = new JLabel("Lame Google Map");
        title.setFont(new Font("verdana", Font.BOLD, 36));
        title.setHorizontalAlignment(JLabel.CENTER);
        JPanel panel = new JPanel(new GridBagLayout());
        panel.add(container);
        JFrame frame = new JFrame();
        frame.add(panel);
        frame.add(title, BorderLayout.NORTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

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

    public class ContainerPanel extends JPanel {

        public ContainerPanel() {
            JLayeredPane layeredPane = new JLayeredPane();
            layeredPane.setPreferredSize(new Dimension(DIM_WIDTH, DIM_HEIGHT));
            BackgroundPanel bg = new BackgroundPanel();
            GroundPanel gg = new GroundPanel();
            ForegroundPanel fg = new ForegroundPanel();

            bg.setBounds(0, 0, DIM_WIDTH, DIM_HEIGHT);
            layeredPane.add(bg, new Integer(1));
            gg.setBounds(0, 0, DIM_WIDTH, DIM_HEIGHT);
            layeredPane.add(gg, new Integer(2));
            fg.setBounds(0, 0, DIM_WIDTH, DIM_HEIGHT);
            layeredPane.add(fg, new Integer(3));
            setLayout(new GridBagLayout());
            add(layeredPane);

            setBorder(new LineBorder(Color.BLUE, 10));
        }
    }

    public class ForegroundPanel extends JPanel {

        public ForegroundPanel() {
            JPanel buttonPanel = new JPanel(new GridLayout(3, 3));
            buttonPanel.setOpaque(false);
            buttonPanel.add(new JLabel());
            buttonPanel.add(new JButton("UP"));
            buttonPanel.add(new JLabel());
            buttonPanel.add(new JButton("Left"));
            buttonPanel.add(new JLabel());
            buttonPanel.add(new JButton("Right"));
            buttonPanel.add(new JLabel());
            buttonPanel.add(new JButton("Down"));
            buttonPanel.add(new JLabel());

            FlowLayout flow = (FlowLayout) getLayout();
            flow.setAlignment(FlowLayout.TRAILING);
            flow.setHgap(0);
            flow.setVgap(0);
            add(buttonPanel);
            setOpaque(false);

        }
    }

    public class GroundPanel extends JPanel {

        Image image = null;

        public GroundPanel() {

            try {
                image = ImageIO.read(getClass().getResource("/resources/california.png"));
            } catch (IOException ex) {
                Logger.getLogger(LayeredPaneDemo.class.getName()).log(Level.SEVERE, null, ex);
            }

            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image, 0, 0, DIM_WIDTH, DIM_HEIGHT, this);
        }
    }

    public class BackgroundPanel extends JPanel {

        public BackgroundPanel() {
            setLayout(new GridBagLayout());
            setBackground(Color.WHITE);
            try {
                Image img = ImageIO.read(getClass().getResource("/resources/google.jpg"));
                add(new JLabel(new ImageIcon(img)));
            } catch (IOException ex) {
                Logger.getLogger(LayeredPaneDemo.class.getName()).log(Level.SEVERE, null, ex);
            }


        }
    }
}


到底什么是
ground
foreground
我感觉你走错了方向。可能会更详细一点,以及实际需求。foreground和ground是属于自定义JLayeredPane的Jpanel对象。我需要的与google maps的外观没有什么不同。它必须是logo作为背景,地图位于地面,HUD位于前景。地图的未加载部分将允许看到徽标。您能详细说明一下吗?我实际上不想清除以前的内容,因为它包括背景。我尝试调用
super.paint()
。仍然不起作用。现在我首先绘制背景,然后调用super,然后在地面和前景调用
paintComponent()
。需要帮助!
图形
是共享资源,这意味着在组件之前绘制的内容仍然“存在”当您收到它时。您必须首先清除它,这就是绘制链所做的。为什么我需要清除它,而所有这些都可以被覆盖?这不是更节省资源吗?还是不会?请回答。谢谢。因为它满足APII的期望。我添加了GetPreferedSize()方法返回完整的正大小,并重写isVisible()始终返回真值。它仍然不起作用。需要帮助!这将解决我的问题,但你确定它是有效的吗?但无论如何,我会尝试它,并让你知道它几个小时。万分感谢。这部分解决了我的问题。但问题是,我也需要在底层添加组件。因此,如果你在
组中添加组件
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Image;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.LineBorder;

public class LayeredPaneDemo {

    public static final int DIM_WIDTH = 600;
    public static final int DIM_HEIGHT = 400;

    public LayeredPaneDemo() {
        ContainerPanel container = new ContainerPanel();
        JLabel title = new JLabel("Lame Google Map");
        title.setFont(new Font("verdana", Font.BOLD, 36));
        title.setHorizontalAlignment(JLabel.CENTER);
        JPanel panel = new JPanel(new GridBagLayout());
        panel.add(container);
        JFrame frame = new JFrame();
        frame.add(panel);
        frame.add(title, BorderLayout.NORTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

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

    public class ContainerPanel extends JPanel {

        public ContainerPanel() {
            JLayeredPane layeredPane = new JLayeredPane();
            layeredPane.setPreferredSize(new Dimension(DIM_WIDTH, DIM_HEIGHT));
            BackgroundPanel bg = new BackgroundPanel();
            GroundPanel gg = new GroundPanel();
            ForegroundPanel fg = new ForegroundPanel();

            bg.setBounds(0, 0, DIM_WIDTH, DIM_HEIGHT);
            layeredPane.add(bg, new Integer(1));
            gg.setBounds(0, 0, DIM_WIDTH, DIM_HEIGHT);
            layeredPane.add(gg, new Integer(2));
            fg.setBounds(0, 0, DIM_WIDTH, DIM_HEIGHT);
            layeredPane.add(fg, new Integer(3));
            setLayout(new GridBagLayout());
            add(layeredPane);

            setBorder(new LineBorder(Color.BLUE, 10));
        }
    }

    public class ForegroundPanel extends JPanel {

        public ForegroundPanel() {
            JPanel buttonPanel = new JPanel(new GridLayout(3, 3));
            buttonPanel.setOpaque(false);
            buttonPanel.add(new JLabel());
            buttonPanel.add(new JButton("UP"));
            buttonPanel.add(new JLabel());
            buttonPanel.add(new JButton("Left"));
            buttonPanel.add(new JLabel());
            buttonPanel.add(new JButton("Right"));
            buttonPanel.add(new JLabel());
            buttonPanel.add(new JButton("Down"));
            buttonPanel.add(new JLabel());

            FlowLayout flow = (FlowLayout) getLayout();
            flow.setAlignment(FlowLayout.TRAILING);
            flow.setHgap(0);
            flow.setVgap(0);
            add(buttonPanel);
            setOpaque(false);

        }
    }

    public class GroundPanel extends JPanel {

        Image image = null;

        public GroundPanel() {

            try {
                image = ImageIO.read(getClass().getResource("/resources/california.png"));
            } catch (IOException ex) {
                Logger.getLogger(LayeredPaneDemo.class.getName()).log(Level.SEVERE, null, ex);
            }

            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(image, 0, 0, DIM_WIDTH, DIM_HEIGHT, this);
        }
    }

    public class BackgroundPanel extends JPanel {

        public BackgroundPanel() {
            setLayout(new GridBagLayout());
            setBackground(Color.WHITE);
            try {
                Image img = ImageIO.read(getClass().getResource("/resources/google.jpg"));
                add(new JLabel(new ImageIcon(img)));
            } catch (IOException ex) {
                Logger.getLogger(LayeredPaneDemo.class.getName()).log(Level.SEVERE, null, ex);
            }


        }
    }
}