Hi all,

I've been trying to paint an image to a JPanel with no success. Could someone help me figure this out?

mport javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.Vector;
import java.awt.image.*;

public class PhoneInterface1 extends JFrame implements ActionListener
{
	private JPanel imagePan = new JPanel(); 
	private JPanel numberPad = new JPanel();
	private JTextArea text = new JTextArea();
	private JDesktopPane desktop;
	private JButton loadButton, closeButton;
	private JLabel status;
	private Vector theFrames;
	private JToolBar theToolBar;
	//public JScrollBar scrollBar = new JScrollBar();
		
	public PhoneInterface1()
	{....................

	public void actionPerformed(ActionEvent e)
	{
		if (e.getSource().equals(loadButton))
		{
			JFileChooser chooser = new JFileChooser();
			int returnVal = chooser.showOpenDialog(this);
    			if(returnVal == JFileChooser.APPROVE_OPTION) 
    			{
            		File f = chooser.getSelectedFile();
            		ImageLoader imgldr = new ImageLoader(f);
            		
            		//PROBLEM HERE!!??
            		
            		imagePanel img = new imagePanel(imgldr); //???
      
            		this.setStatus("Loading Image "+f.getName());
    			}
		}

class ImageLoader extends JFrame
{
	private String filename;
	private String directory;
	private Image theImage;
	private int width, height;
	private long fileLength;

	public ImageLoader(File f)
	{
		
		filename = f.getName();
		directory = f.getPath();	
		fileLength = f.length();	

	 	this.theImage = this.getToolkit().getImage(directory);
		JScrollPane scroll = new JScrollPane(new JLabel(new  ImageIcon(this.theImage)));

		this.getContentPane().setLayout(new BorderLayout());
		this.getContentPane().add("North", new JLabel(filename));
		this.getContentPane().add("Center",scroll);
		
		width = this.theImage.getWidth(null);
		height = this.theImage.getHeight(null);
		//String details = new String(" Details: Image Size("+width+","+height+") File Size "+fileLength+" bytes");
		//this.getContentPane().add("North", new JLabel(details));
		
		this.setSize(300,300);
		//this.show();	
	}

class imagePanel extends JPanel
{	BufferedImage image;
	public void paintComponent(Graphics g) 
	{
		super.paintComponent(g);
		if(image != null) 
		{
			g.drawImage(image, 0, 0, this);
		}
	}
}

I created the class imagePanel to draw an image to a panel. I load an image from file using the ImageLoader class and I want to draw it on the JPanel "imagePan" in the PhoneInterface1 class. I'm having trouble going from an ImageLoader object to drawing the image on imagePan in the PhoneInterface1 class. The problem area is marked by "//PROBLEM HERE!!??" in the code above.
Apologies in advance if this post seems a bit messy, but an expert advice would be grreatly appreciated!

Your ImageLoader needs a getImage() method that returns the Image object. Then it's just a matter of calling imgldr.getImage().

You seem to have nested the classes more than necessary, but that may just be the way you pasted in the code. Anyway, if you want to construct an ImagePanel with the image, you will need to write that constructor in your ImagePanel class as well.

Thanks Ezzaral for your reply. I'm just going to try what you said now. Thanks to you to for your suggestion Frederik. I'm not sure how f.absolutePath would work in adding an image to a JPanel though? It just returns the path name of the file at the time it was constructed..

Hi Ezzaral, Frederik, all,

I don't think I can use the getImage() method as I have to use swing to build my interface. So getImage() isn't defined for my ImageLoader class, as it is a child of JFrame. Any other ideas??

Hi Ezzaral, Frederik, all,

I don't think I can use the getImage() method as I have to use swing to build my interface. So getImage() isn't defined for my ImageLoader class, as it is a child of JFrame. Any other ideas??

You can add any method you like to ImageLoader - it's your own creation. The entire reason for extending a class is to add additional functionality to it. That said, I still don't see why ImageLoader should extend JFrame for that matter. What does image loading have to do with a frame, especially if you are using it to load an image to place into a different panel class?

Using Swing for your application in no way implies that every one of your classes needs to extend a Swing component. Most of your classes will be dedicated to handling state and behavior that is completely independent of a visual presentation component.

Is ImageLoader supposed to do anything except get an image from a file? If not, then it really doesn't even need to be a class at all. Just make it a method in your other class that returns an Image for a given file name parameter.

Comments
Helpful!

What about this : can it be helpfull ?
Just make sure you first can load the image to the JPanel ...

import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import java.awt.Graphics;
import javax.swing.*;
import javax.swing.JApplet;
import java.util.Vector;




public class nio2 extends JApplet implements Runnable , ActionListener{ 
	static final long serialVersionUID = -116069779446114664L;
    

JButton b1;
Toolkit tk;
JLabel lab;
Image plaat;
ImageIcon imic;
Container ctain;
Graphics g;
	public void init()
	{
		
		
		ctain=getContentPane();
		
		
		
		b1=new JButton("Load  ");
		b1.setBounds(200, 10, 180, 60);
		b1.addActionListener(this);
        ctain.add(b1);
		
		lab=new JLabel("here image");
		lab.setBounds(200, 220, 300, 250);
		ctain.add(lab);
	
		this.setBackground(Color.lightGray);
		
		
		
		
		
	}
	
   
	   
	
   
   
	public void start(){
		
	}
	public void run(){
		
	}
	
	
	public void actionPerformed(ActionEvent e){
		
		
		
if(e.getSource()==b1){
			
			try{
				
			lab.setIcon(new ImageIcon("C:\\test.gif"));
			
			}catch(Exception ex4){}
			
		}



	
	
}}

Hi Ezzaral,

You're right about making a class for loading images and having it extend JFrame. I had also thought of just creating a method to load an image within my PhoneInterface class, but unfortunately didn't have the knowhow to do it.
Thanks for your insights on creating classes too. It makes sense that just because I'm using swing, every class doesn't necessarily have to extend a swing component. The reason I said this in the first place was that when I looked up getImage() in the API doc, it said that it was a method of the Applet class, so I thought that this wouldn't be compatible with swing components. I realise my errors now though, although I'm not really sure why. No need to explain, I'll do the reading myself.
I did create a method for imageLoader within my PhoneInterface class:

public Image imageLoader(File f)
{	
	filename = f.getName();
	directory = f.getPath();	
	Image image;
	
	this.img = this.getToolkit().getImage(directory);
	image = this.img;
	
	return image;
}

So, provided that this is right (no syntax errors anyways:)), I should be able to call the DrawImage class to draw this image:

class DrawImage extends JPanel
{	BufferedImage img;
	public void paintComponent(Graphics g) 
	{
		super.paintComponent(g);
		if(img != null) 
		{
			g.drawImage(img, 0, 0, this);
		}
	}
}

Then all that's left to do is call on this class from within my actionPerformed method to draw this image to the JPanel "imagePanel" when the button "loadButton" is pressed. This is where I am now stumped once again! :( I think I have to call the image loader method and pass the returned image to another call on the DrawImage class, which would be instructed to draw the image on "imagePanel". The problem is that I don't know how to do this? I tried:

loadedImage = imageLoader().getImage();
imagePan = new JPanel().DrawImage(loadedImage);

but I got an error for the lack of arguements for "imageLoader" and another saying that "DrawImage" is undefined for JPanel. I can sort of understand why I'm getting these errors, but I'm all out of ideas how to sort it out! Suggestions would be much appreciated!

G.

p.s. Thanks Ezzaral and Frederik for your insights. That looked like some hardcore Java Frederik.. way beyond this newbie!! :)

It's getting closer, but it looks like you are still a little bit confused on using methods and classes. I think it we rename a few things it will clarify their intent.

Class names are usually nouns, because they represent "things". Let's rename the DrawImage class to ImagePanel, because that is what it actually is: a panel that shows an image. DrawImage sounds a bit like a method that would draw an image and is a little misleading.

Method names should be verbs, because they represent actions you wish to take. Methods "do "stuff", so we name them to clearly indicate what they do. So let's rename the imageLoader() method to loadImage() or perhaps getImage(). It's now clear that we are performing an action to load an image when we call that method. Let's also move the method into the ImagePanel class since that is the "thing" that really needs to load an image. The PhoneInterface doesn't need to load an image itself and shouldn't have to worry about what the image panel needs to do for itself. That's why we create separate classes in the first place: to group together specific pieces of functionality with clearly defined roles and responsibilities. One class should keep out of other classes' business as much as possible.

So now we have an ImagePanel that has a method to load an image from a file. The ImagePanel has a variable to hold that image so it can paint it whenever it needs to. Since it can't paint a null image, we need the constructor of the ImagePanel to make sure its internal state (variables) is in order before it's called upon by anything else to do something. So we put the following constructor into the ImagePanel

class ImagePanel extends JPanel {
    Image img;
    
    public ImagePanel(){
        // make sure the parent JPanel constructor is called
        // so it does whatever it needs to do first.
        super();
        
        img = loadImage("whatever.file");
    }
    
	public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(img != null) {
            g.drawImage(img, 0, 0, this);
        }
    }
    
    public Image loadImage(File f) {
        Image image = getToolkit().getImage(f.getPath());        
        return image;
    }
}

Now our ImagePanel class can fulfill its defined role all on it's own. Perhaps you want an ImagePanel to be able to display any image you tell it to. You can modify its constructor to take the file name as a parameter and use that when you call loadImage(). Perhaps you want to set a new image without creating a completely new panel. You could add a method setImage(File) that loads up a new image from that File and then calls repaint() to display the new image.

Comments
Great explanation of methods and classes, Ezz

Hello i have coded for hours and hours but no result ... so i am leaving this subject...
Succes with it ! Sorry for my posts they make no much sense ...

Maybe maybe laterzzzz bye

Hi Ezzaral,

Thanks a million for your help once again. I took a bit of a break at it there for Christmas, hope you all had a good one! I tried what you suggested, but I got an error corresponding to the loadImage method:

"The method loadImage(File) in the type ImagePanel is not applicable for the arguements (string)".

Did you mean for me to write my own method to load an image within the ImagePanel class?

You'll just need to pass a File instance (i.e. loadImage(new File("someFile.jpg")) instead of the string path or you can alter the loadImage() method to take a string path instead if you prefer it. It was a mistake in the method parameter on my part.

Yep, that solved that problem alright, thanks for that! I've got a null pointer exception now which I can't figure out. It's weird, because my interface loaded fine before, but now this null pointer exception has just appeared out of nowhere. This is my code:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.Vector;
import java.awt.image.*;

public class PhoneInterface1 extends JFrame implements ActionListener
{
	private JPanel imagePan; 
	private JPanel numberPad = new JPanel();
	private JTextArea text = new JTextArea();
	private JButton loadButton, closeButton;
	private JLabel status;

	public PhoneInterface1()
	{		
		status = new JLabel();

		this.text = new JTextArea(5,5);

		JScrollBar vBar = new JScrollBar(JScrollBar.VERTICAL);
		
		this.text.setWrapStyleWord(true);
		this.text.setLineWrap(true);
		
		JButton[] buttons = new JButton[15];
		
		numberPad.setLayout(new GridLayout(5,3));
		for(int i=0; i<15; i++)
		{ 
			if (i==0){ 
				buttons[i] = new JButton("Load Image",new ImageIcon("load.gif"));
				loadButton = buttons[i]; 
				buttons[i].addActionListener(this);	
			}
			else if (i==1){
				buttons[i] = new JButton("Menu");
				buttons[i].addActionListener(this);
			}
			else if	(i==2){
				buttons[i] = new JButton("Close All");
				closeButton = buttons[i];
				buttons[i].addActionListener(this);
			}
			else if (i>2 && i<12){
				buttons[i] = new JButton(""+(i-2));
				buttons[i].addActionListener(this);
			}
			else if (i==12){
				buttons[i] = new JButton(""+"*");
				buttons[i].addActionListener(this);
			}
			else if (i==13){
				buttons[i] = new JButton(""+0);
				buttons[i].addActionListener(this);
			}
			else if (i==14){
				buttons[i] = new JButton(""+"#");
				buttons[i].addActionListener(this);
			}
			numberPad.add(buttons[i]);
		}
					
		this.setSize(400,400);	// set the size to 400 x 400
		this.show();		// display the frame
		this.setStatus("Application Started");
		
		this.add("North", imagePan);
		this.add("Center", text);
		this.add("South", numberPad);
		this.getContentPane().add("East",vBar);
		
		this.pack();
		this.setVisible(true); //displays the frame
	}
	
	public void actionPerformed(ActionEvent e)
	{
		Image loadedImage;
		
		if (e.getSource().equals(loadButton))
		{
			JFileChooser chooser = new JFileChooser();
			int returnVal = chooser.showOpenDialog(this);
    			if(returnVal == JFileChooser.APPROVE_OPTION) 
    			{
            		     
    				new ImagePanel();
 
    			}
		}
	}
	
	private void setStatus(String s)
	{
		this.status.setText("Status: "+s);
	}
	
	public static void main(String args[])
	{
	   new PhoneInterface1();
	}
}

class ImagePanel extends JPanel {
	Image img;
	public ImagePanel(){
		
		// make sure the parent JPanel constructor is called
		// so it does whatever it needs to do first.
		super();
		
		img = loadImage(new File("swim.jpg"));
	}
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		if(img != null) {
			g.drawImage(img, 0, 0, this);
		}
	} 
	public Image loadImage(File f) {
		Image image = getToolkit().getImage(f.getPath());

		return image;
	}
}

I'm getting the error on lines 69 and 102. I might also be trying to call the ImagePanel class incorrectly, as I use "new ImagePanel();" in the PhoneInterface1 class. Would I subsequebtly have to call the paintComponent and loadImage methods?

You are getting the error because on line 69 you are adding "imagePan" to the frame but you have not initialized imagePan yet.

Also, on line 89, you don't need to create a new ImagePanel. Just call imagePanel.loadImage(File) to load a new image in the panel.

If you need ImagePanel to remain blank until the button is pressed, take the code that loads the image out of the ImagePanel constructor.

This article has been dead for over six months. Start a new discussion instead.