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

时间:2014-03-31 16:47:20

标签: java paint layer pane

所以我在这里开展一个需要自定义JLayeredPane类的项目。 它有两个成员“地面”和“前景”JPanel和一个背景(Image)成员。

它应该显示的方式是应该绘制背景图像,然后在它顶部绘制地面的所有组件,然后在顶点处绘制前景的组件。所以前景掩盖了覆盖背景的地面。背景应仅显示在地面和前景中没有Component的地方或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()函数来检查地面和前景实际上是否包含组件而它们确实存在。但他们只是没有表现出来。

有人可以帮我吗?

2 个答案:

答案 0 :(得分:1)

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

为了绘制背景,你应该使用paintComponent,它用于绘制组件的背景。

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

绘制组件实际上更复杂

仔细查看Custom PaintingPainting in Swing and AWT

根据代码段进行了更新

Screen范围内的Container,你正在做......

@Override
public void paint(Graphics g) {
    super.paint(g);
    GraphicsUtilities.drawPictureTiled(background, g);
    paintComponents(g);
    g.dispose();
}
  • 不要致电paintComponentssuper.paint已经这样做了。
  • 请勿在{* 1}}上下文中致电dispose
  • 根据我的其他示例代码,您应该从Graphics延伸并覆盖JPanel。这将允许您置于组件层

由于paintComponentGroundPanel都是ForeGroundPanel,因此无需自己绘制它们。实际上,您只需使用JPanel甚至是OverlayLayout,然后将它们直接添加到GridBagLayout,而NestedScreen本身就是一个容器......

因此,我删除了您的示例代码,以便我可以使用缺少的代码作为示例。我有点想象,只是让JPanel充当暂停画面

Pony 1 Pony 2

这一切都是通过使用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);
            }
        }
    }

}

看看Painting in AWT and SwingPerforming Custom Painting,了解绘画在Swing中是如何运作的。

一个基本的想法是避免使用所有这些复合或嵌套组件,而是创建一个引擎,可以将图层直接绘制到Graphics上下文,甚至可以绘制到BufferedImage你的{{1}}可以将油漆涂在单个组件上......

答案 1 :(得分:0)

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

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

  • 创建另一个地面面板,您也可以在其中绘制某些内容(在下面的示例中,如果GroundPanel仅绘制了bugs bunny的图像。

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

  • 所有小组' opaque属性应设置为false,以允许其后面的面板显示在任何透明度下。

enter image description here

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class ThreeTier {

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

    private BufferedImage backgroundImage;
    private BufferedImage groundImage;
    private BufferedImage foregroundImage;

    public ThreeTier() {
        initImages();
        JFrame frame = new JFrame();
        frame.setContentPane(new BackgroundPanel());
        frame.add(new GroundPanel());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private void initImages() {
        try {
            backgroundImage = ImageIO.read(getClass().getResource("/resources/background.png"));
            foregroundImage = ImageIO.read(getClass().getResource("/resources/foreground.png"));
            groundImage = ImageIO.read(getClass().getResource("/resources/bugsBunny.png"));
        } catch (IOException ex) {
            Logger.getLogger(ThreeTier.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    class BackgroundPanel extends JPanel {

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

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(ThreeTier.DIM_WIDTH, ThreeTier.DIM_HEIGHT);
        }
    }

    class GroundPanel extends JPanel {

        private static final String RIGHT_ACTION = "rightAction";
        private int imageX = 50;
        private int imageY = 140;

        public GroundPanel() {
            setOpaque(false);
            add(new ForegroundPanel());

            InputMap im = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
            im.put(KeyStroke.getKeyStroke("RIGHT"), RIGHT_ACTION);
            getActionMap().put(RIGHT_ACTION, new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    if (imageX >= DIM_WIDTH) {
                        imageX = 0 - groundImage.getWidth();
                        repaint();
                    } else {
                        imageX += 10;
                        repaint();
                    }

                }
            });
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(groundImage, imageX, imageY, groundImage.getWidth(), groundImage.getHeight(), this);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(ThreeTier.DIM_WIDTH, ThreeTier.DIM_HEIGHT);
        }
    }

    class ForegroundPanel extends JPanel {

        public ForegroundPanel() {
            setOpaque(false);
            setLayout(new FlowLayout(FlowLayout.TRAILING, 10, 0));
            JButton button = new JButton("I'm in the Foreground!");
            add(button);
        }

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

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(ThreeTier.DIM_WIDTH, ThreeTier.DIM_HEIGHT);
        }
    }

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

<强>更新

当然,你总是可以使用 JLayeredPane。这就是它的用途。见这个例子

enter image description here

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);
            }


        }
    }
}