-3

I have been trying this for hours now. I have a class that extends JComponent, and in its paintComponent I am trying to draw an image, but I am not being able to. Here is my code:

public class Main extends JComponent{



public static void main(String[] args) {

    Main main = new Main();

    JFrame frame = new JFrame(Info.getGameTitle());
    frame.add(main);

    frame.setSize(Info.getWidth(), Info.getHeight());
    frame.setResizable(false);

    frame.addWindowListener(new WindowAdapter(){
        public void windowClosing(WindowEvent e){
            System.out.println("Window closed");
            System.exit(0);
        }
    });

    frame.setAlwaysOnTop(true);
    frame.setFocusable(true);
    frame.setAutoRequestFocus(true);
    frame.setLocationRelativeTo(null);

    frame.setVisible(true);

    Graphics g = main.getGraphics();

    main.paint(g);


}

public void paintComponent(Graphics g) {
    super.paintComponent(g);

    BufferedImage image = null;
    try {
        image = ImageIO.read(new FileInputStream("images/01.jpg"));
    }catch(FileNotFoundException e) {
        System.out.println("Could not find file!");
        e.printStackTrace();
    }catch(IOException e) {
        System.out.println("Could not read file!");
        e.printStackTrace();
    } 

    g.drawImage(image, 0, 0, this);


    }
}

It is not throwing any exceptions, so the image appears to be loaded. However, nothing appears on the screen. If I try to draw shapes or text, that works fine. What am I doing wrong?

EDIT: Now I have supplied a working example.

  • 1
    Consider providing a [runnable example](https://stackoverflow.com/help/mcve) which demonstrates your problem. This is not a code dump, but an example of what you are doing which highlights the problem you are having. This will result in less confusion and better responses – MadProgrammer Jan 27 '17 at 22:20
  • Be aware that `paintComponent` will be called *very* often,. Hence, it is no good idea to do time-consuming things (like reading an image file) there – Thomas Fritsch Jan 27 '17 at 22:21
  • What's wrong with a `JLabel`? – MadProgrammer Jan 27 '17 at 22:21
  • For [example](http://stackoverflow.com/questions/31931943/drawing-an-image-on-top-of-an-image-in-a-jcomponent-erases-part-of-the-bottom-im/31932127#31932127), [example](http://stackoverflow.com/questions/13791984/add-an-background-image-to-a-panel/13792503#13792503) – MadProgrammer Jan 27 '17 at 22:25
  • I tested a variant of your code and it works fine for me – MadProgrammer Jan 27 '17 at 22:28
  • I've edited my code, now it's a working example – Nicolas Martorell Jan 27 '17 at 22:30
  • I tried using a JLabel before but it didn't change anything. – Nicolas Martorell Jan 27 '17 at 22:32

4 Answers4

1
Graphics g = main.getGraphics();
main.paint(g);

No, no, no, NO, NO! A infinite times NO! This is not how painting works!

Take a look at Performing Custom Painting and Painting in AWT and Swing for a better understanding of how painting works in Swing.

getGraphics can return null and will only return the last used context to paint the component, anything painted to it will be erased on the next paint cycle.

There is never a good reason to call paint manually, just don't do it.

You should be do something more along the lines of

Example output

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

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

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

    public class TestPane extends JPanel {

        private BufferedImage img = null;

        public TestPane() {
            try {
                img = ImageIO.read(new FileInputStream("..."));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

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

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (img != null) {
                g2d.drawImage(img, 0, 0, this);
            }
            g2d.dispose();
        }

    }
}

If your image is still not showing up, I suspect that the image is misplaced.

new FileInputStream("images/01.jpg")

suggests that the image resides within the current directory from where the program is been executed, this is not always the same as where the program resides.

You can use System.getProperty("user.dir") to determine the current "working" directory and compare it to where you think the program resides. You can also use File#exists to test if the file exists or not, although, I would have expected the code to throw an IOException if that were the case.

A better long term solution would be to embedded the image within application (typically including it in the Jar), this removes the above issues.

In that case you'd need to use...

ImageIO.read(getClass().getResource("/images/01.jpg"));

to load the image

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Okay, what I don't understand about this is, you override paintComponent but as far as I can see it never gets called. Or something else calls it automatically? – Nicolas Martorell Jan 27 '17 at 22:40
  • See [Painting in AWT and Swing](http://www.oracle.com/technetwork/java/painting-140037.html) and [Performing Custom Painting](http://docs.oracle.com/javase/tutorial/uiswing/painting/) for more details about how painting works in Swing – MadProgrammer Jan 27 '17 at 22:42
  • Can anyone explain the reason for the downvote? Since the question has not received any new downvotes or any new close votes, it can't be cause the question is invalid. Since none of the other answers have received downvotes (and fail to solve the problem) I can only assume you have a personal vendetta against me and/or don't actually understand the question/problem and the answer – MadProgrammer Jan 27 '17 at 22:44
  • 1
    Maybe your image isn't as sexy as the pengüin you have on your profile :P (1+ for the pic and good explanation) – Frakcool Jan 27 '17 at 22:46
  • **Much** better. Objection removed. – Hovercraft Full Of Eels Jan 27 '17 at 22:47
  • @NicolasMartorell My gut feeling is that there is an issue with your image – MadProgrammer Jan 27 '17 at 22:54
  • Yes, this is what's happening now: I realised that if a drew a shape and then on top I drew an Image, the shape did not appear on screen (so something WAS being drawn, but I couldn't see it). I changed the format of my image to .gif and it works, but the image is super small (and if I scale it, of course, it's very pixelated). I tried then with .jpg, .bmp and .png and non of them work, they all cause the same problem! – Nicolas Martorell Jan 27 '17 at 23:15
  • I also noticed that the gif file is way smaller (12 kb) than the other files, which are more than 1 mb each. Maybe it's a memory problem? Or a format problem? It's clearly not a problem with the rendering process in general. – Nicolas Martorell Jan 27 '17 at 23:15
  • I just tried with a bigger .gif and it failed as well. It is a memory problem. Does anybody know what exactly is causing it, and what can I do to fix it? – Nicolas Martorell Jan 27 '17 at 23:21
  • @NicolasMartorell How big is the image (in pixels, width/height)? – MadProgrammer Jan 27 '17 at 23:48
  • 2576x1932 pixels. If that's the problem, is it impossible to load an image that size? – Nicolas Martorell Jan 27 '17 at 23:53
  • @NicolasMartorell I wouldn't think so, let me try some experiments – MadProgrammer Jan 27 '17 at 23:54
  • I am now playing with the size of the image and it really seems to be it. 1024x768 is totally fine. I mean, the problem is solved because that is quite enough for what I am doing, but it's still weird that this has been a problem at all. – Nicolas Martorell Jan 28 '17 at 00:03
  • @NicolasMartorell I just tested an image of 7680x4800 @ 300dpi, and while I took a little while to load, it worked fine, but yes, memory would be an issue, although I'd expect some kind of exception to be thrown. Most image formats are compressed, so the size on disk does not equate to the amount of memory you'll need to display it ;) – MadProgrammer Jan 28 '17 at 00:22
1

Be aware that your JComponent may be painted hundreds of times per second, for example when it is partially obscured by another moving window. So, performance of the paint methods is important, or else you get a "laggy" GUI.

Therefore I suggest to separate the time-consuming part (i.e. reading the image file) from the JComponent.

public class ImageComponent extends JComponent {

    private BufferedImage image;

    public void setImage(final BufferedImage image) {
        this.image = image;
        repaint();
    }

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

Somewhere else in your code you read the image file and set it into the component:

BufferedImage image = null;
try {
    image = ImageIO.read(new File(fullpathname+"/01.jpg"));
}catch(Exception e) {
    System.out.println("Could not read file!");
    e.printStackTrace();
} 
ImageComponent component = new ImageComponent();
component.setImage(image);
Thomas Fritsch
  • 9,639
  • 33
  • 37
  • 49
  • I added this for the component to have a proper size: `@Transient() @Override public Dimension getPreferredSize() { return new Dimension(200, 200); }` – nolisj Oct 23 '21 at 07:20
0

Try this

   BufferedImage image = null;
    try {
        image = ImageIO.read(new File(fullpathname+"/01.jpg"));
    }catch(Exception e) {
        System.out.println("Could not read file!");
        e.printStackTrace();
    } 

public void paintComponent(Graphics g) {
    super.paintComponent(g);


    g.drawImage(image, 0, 0, this);


}

read throws more exceptions

IllegalArgumentException - if input is null.
IOException - if an error occurs during reading.

so catching the more general one (Exception) will cover it

gpasch
  • 2,672
  • 3
  • 10
  • 12
  • *"It is not throwing any exceptions"* - would suggest that the image is been loaded and using `FileInputStream` works fine - [`ImageIO.read(InputStream)`](https://docs.oracle.com/javase/7/docs/api/javax/imageio/ImageIO.html#read(javax.imageio.stream.ImageInputStream)) – MadProgrammer Jan 27 '17 at 22:29
  • "It is not throwing any exceptions" - would suggest that the image is been loaded : check your papers – gpasch Jan 27 '17 at 22:38
0

Try this:

Image image = ImageIO.read(new File(file)); g.drawImage(image, 0, 0, this);