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