Java: Image Not Displaying

2019-09-07 00:45发布

问题:

I am making a program where I need to display an image. I am using the ImageIcon and Image classes in order to do this. I declared the ImageIcon in the constuctor and then assigned the images value through i.getImage(). Everything but the image seems to be loading fine. Here is my code:

UPDATE: I have the image in the same directory as the code. I am using a mac and I have tried "image.png", "./image.png", "Users/myStuff/Documents/workspace/Game/src/image.png". Niether of these have worked.

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;
import javax.swing.JFrame;

@SuppressWarnings("serial")
public class Game extends JFrame {

    int x = 100, y = 100;

    private Image dbimage;
    private Graphics dbg;

    Image image;

    class AL extends KeyAdapter {

        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();
            if (keyCode == e.VK_LEFT) {
                if (x <= 20) {
                    x = 20;
                } else {
                    x -= 5;
                }
            } else if (keyCode == e.VK_RIGHT) {
                if (x >= 230) {
                    x = 230;
                } else {
                    x += 5;
                }
            } else if (keyCode == e.VK_UP) {
                if (y <= 20) {
                    y = 20;
                } else {
                    y -= 5;
                }
            } else if (keyCode == e.VK_DOWN) {
                if (y >= 230) {
                    y = 230;
                } else {
                    y += 5;
                }
            }
        }

    }

    public Game() {

        //load up image
        ImageIcon i = new ImageIcon("image.png");
        image = i.getImage();

        //set up properties
        addKeyListener(new AL());
        setTitle("Game");
        setSize(250, 250);
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBackground(Color.CYAN);
        setVisible(true);

    }

    public void paint(Graphics g) {
        dbimage = createImage(getWidth(), getHeight());
        dbg = dbimage.getGraphics();
        paintComponent(dbg);
        g.drawImage(dbimage, 0, 0, this);
    }

    public void paintComponent(Graphics g) {
        g.setFont(new Font("Arial", Font.BOLD | Font.ITALIC, 30));
        g.setColor(Color.MAGENTA);
        g.drawString("Hello World!", 50, 50);
        g.setColor(Color.RED); 
        g.drawImage(image, 100, 100, this);
        repaint();
    }

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

}

回答1:

Significant issues with your code above...

first and foremost, if your image is with your class files, then don't get it as a File, but rather get it as a resource as MadProg shows (and as most similar questions on this site will tell you):

    // get your image as a resource
    URL resource = Game.class.getResource(RESOURCE_PATH);
    BufferedImage img = null;
    try {
        // read in using ImageIO
        img = ImageIO.read(resource);
    } catch (IOException e) {
        e.printStackTrace();
        System.exit(-1);
    }

Next of all, never draw directly within the JFrame and certainly not within its paint method. Instead check out the Swing drawing tutorials and follow their lead: draw within the paintComponent method of a JPanel, but only after calling the super's paintComponent method so that the painting can continue down the line of the painting chain.:

// draw within the paintComponent method, not the paint method
@Override
protected void paintComponent(Graphics g) {
    // call the super's method to all painting to chain down the line
    super.paintComponent(g);
    if (dbimage != null) {
        g.drawImage(dbimage, imgX, imgY, this);
    }
}

I prefer to override the JPanel's getPreferredSize when fixing the sizes of my GUI, something like:

// set the preferred size of the main Game JPanel safely 
@Override
public Dimension getPreferredSize() {
    if (isPreferredSizeSet()) {
        return super.getPreferredSize();
    }
    return new Dimension(PREF_W, PREF_H);
}

Put all together, something like so might work:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.*;

public class Game extends JPanel {
    public static final String RESOURCE_PATH = "image.png";
    private static final int PREF_W = 400;
    private static final int PREF_H = PREF_W;
    private BufferedImage dbimage = null;
    private int imgX = 0;
    private int imgY = 0;

    public Game(BufferedImage dbimage) {
        this.dbimage = dbimage;
    }

    // draw within the paintComponent method, not the paint method
    @Override
    protected void paintComponent(Graphics g) {
        // call the super's method to all painting to chain down the line
        super.paintComponent(g);
        if (dbimage != null) {
            g.drawImage(dbimage, imgX, imgY, this);
        }
    }

    // set the preferred size of the main Game JPanel safely 
    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }

    private static void createAndShowGui() {
        // get your image as a resource
        URL resource = Game.class.getResource(RESOURCE_PATH);
        BufferedImage img = null;
        try {
            // read in using ImageIO
            img = ImageIO.read(resource);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }

        // pass image into your Game JPanel
        Game mainPanel = new Game(img);

        // pass the JPanel into a JFrame
        JFrame frame = new JFrame("Game");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);  // and display it
    }

    public static void main(String[] args) {
        // start your Swing GUI in a thread-safe manner
        SwingUtilities.invokeLater(() -> {
            createAndShowGui();
        });
    }
}

Next look up Key Bindings to help you to do animation with key strokes with this GUI