在JComponent中在图像上绘制图像会擦除底部图像的一部分

时间:2015-08-11 01:49:57

标签: java image swing bufferedimage paintcomponent

我正在进行2D游戏,我需要在另一个上面绘制图像。在我绘制第一个图像(较大的一个,jpg)之后,第二个图像(较小的一个,png)从第二个图像到右下角的位置擦除。像这样:

enter image description here

我已经对此进行了一些研究,并且有人建议我使用缓冲图像,所以我用两个图像做了这个,问题仍然存在。这是我看过的一篇文章:How to draw an image over another image?。我也看到有人建议使用graphics2d,虽然我不太明白使用它们的原因或如何使用它们。我是java图形和图像的新手,所以这可能是一个愚蠢的错误。 这是我的代码。谢谢。

import java.awt.*;
import java.awt.event.*;
import java.net.*;
import javax.swing.*;
import java.util.ArrayList;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.IOException;

public class DisplayExample extends JComponent
{
private BufferedImage backgroundImage;
private String backgroundName;

private BufferedImage image;  //image to draw
private int imageX;  //position of left edge of image
private int imageY;  //position of top edge of image

private JFrame frame;

public static void main(String[] args)
{
    DisplayExample example = new DisplayExample();
    example.run();
}

public DisplayExample()
{
    imageX = 200;
    imageY = 200;

    backgroundName = "backgroundShip.jpg";
    URL backgroundURL = getClass().getResource(backgroundName);
    if (backgroundURL == null)
        throw new RuntimeException("Unable to load:  " + backgroundName);
    try{backgroundImage = ImageIO.read(backgroundURL);}catch(IOException ioe){}
    //load image

    String fileName = "explosion.png";
    URL url = getClass().getResource(fileName);
    if (url == null)
        throw new RuntimeException("Unable to load:  " + fileName);
    //image = new ImageIcon(url).getImage();
    try{image = ImageIO.read(url);}catch(IOException ioe){}
    System.out.println(image instanceof BufferedImage);
    setPreferredSize(new Dimension(1040,500));  //set size of drawing region

    //need for keyboard input
    setFocusable(true);  //indicates that WorldDisp can process key presses

    frame = new JFrame();
    frame.getContentPane().add(this);
    frame.pack();
    frame.setVisible(true);
}

public void paintComponent(Graphics g)
{

    super.paintComponent(g);
    if(backgroundImage != null)
        g.drawImage(backgroundImage,0,0,getWidth(), getHeight(), null);
    g.drawImage(image, imageX, imageY, this);  
}

public void run()
{ 
    while(true)
    {
    imageY+=1;
    repaint();
    try{Thread.sleep(100);}catch(Exception e){}
    }
}

}

1 个答案:

答案 0 :(得分:1)

所以我拿了你的代码,添加了我自己的图片,它运行正常。

话虽如此,有些方面可以改进:

  • 您冒着阻止事件调度线程或使用run方法将线程竞争条件引入代码的风险。您应该考虑使用Swing Timer。有关详细信息,请参阅How to use Swing Timers。这允许您安排在EDT上下文中调用的常规回调,使更新UI的上下文更安全
  • 您应该只在EDT的上下文中创建或修改UI的状态,Swing不是线程安全的。有关详细信息,请参阅Initial Threads。众所周知,Swing有"问题"当UI未在EDT中初始化时
  • 缩放图像非常昂贵,您应该避免在paint方法中这样做,而是缩放图像并保留对结果的引用,并在需要绘制时使用它。
  • 您应该考虑使用KeyListener上的密钥绑定API,它将解决与使用KeyListener相关的许多问题。有关详细信息,请参阅How to Use Key Bindings

例如......

Pony Up

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class DisplayExample extends JComponent {

    private BufferedImage backgroundImage;
    private String backgroundName;

    private BufferedImage image;  //image to draw
    private int imageX;  //position of left edge of image
    private int imageY;  //position of top edge of image

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                DisplayExample example = new DisplayExample();

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(example);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public DisplayExample() {
        imageX = 200;
        imageY = 200;

        try {
            backgroundImage = ImageIO.read(new File("..."));
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        //load image

        try {
            image = ImageIO.read(new File("..."));
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }

        //need for keyboard input
        //setFocusable(true);  //indicates that WorldDisp can process key presses
        // Use the key bindings API instead, causes less issues
        Timer timer = new Timer(100, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                imageY += 1;
                repaint();
            }
        });
        timer.start();
    }

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

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        if (backgroundImage != null) {
            // Scaling is expensive, don't do it here
            int x = (getWidth() - backgroundImage.getWidth()) / 2;
            int y = (getHeight() - backgroundImage.getHeight()) / 2;
            g2d.drawImage(backgroundImage, x, y, this);
        }
        g2d.drawImage(image, imageX, imageY, this);
        g2d.dispose();
    }
}