Hello everyone.
I just started on 'converting' my multiplayer text RPG
into a graphical form.

What I am trying to do is this:
Create a title window, basicly just a JPanel with one image filling the space.
To this JPanel I add a MouseListener.
When a user clicks the window and thus the panel, I change the Image to draw
to just the background image, ie no text, and then call repaint();

However what happens, is that I have to click the panel twice for the background Image to appear. After the first click I just get the JPanel's background color.

My code looks like this:

The JFrame

import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.Toolkit;
import javax.swing.*;

public class MainWindow extends JFrame {
	
	private static final long serialVersionUID = 1L;
	
	public MainWindow(String title){
		
		setSize(640,400);
		setTitle(title);
		setResizable(false);
		
		
		Image titleScreen = Toolkit.getDefaultToolkit().getImage("starting screen_2.jpg");
		
		MainWindowCanvas board = new MainWindowCanvas(titleScreen);
		getContentPane().add(board,BorderLayout.CENTER);

		setLocationRelativeTo(null);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setVisible(true);
		
	}
	
	
	public static void main(String[] args){
		new MainWindow("Celegoth");
	}
}

The JPanel

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class MainWindowCanvas extends JPanel implements MouseListener{

	/**
	 * 
	 */
	private static final long serialVersionUID = 9111698527897284505L;
	private Image mainTitleScreen,mainMenuScreen;
	
	public MainWindowCanvas(Image im){
		
		setLayout(null);
		addMouseListener(this);
		setBackground(Color.black);
		mainTitleScreen = im;
		mainMenuScreen = Toolkit.getDefaultToolkit().getImage("Starting screen background.jpg");
		repaint();
	}
	
	public void paintComponent(Graphics g){
		super.paintComponent(g);
		g.drawImage(mainTitleScreen, 0, 0, null);
	}
	
	public void mouseClicked(MouseEvent arg0) {

	}

	public void mouseEntered(MouseEvent arg0) {

	}

	public void mouseExited(MouseEvent arg0) {

		
	}

	public void mousePressed(MouseEvent arg0) {
		mainTitleScreen = mainMenuScreen;
		repaint();
	}

	public void mouseReleased(MouseEvent arg0) {

	}

}

If I put a JOptionPane.showMessageDialog of some sort in between there, for example in the mousePressed method, so that the paintComponent gets called twice, there's no problem.

But I want to understand what's happening, so I can avoid mistakes in the future.

Thanks for reading, and hopefully until soon.

Aviras

I'm afraid that didn't change anything, however thank you for the swift reply.

I put the revalidate over here, so perhaps you meant something else:

public void mousePressed(MouseEvent arg0) {
		mainTitleScreen = mainMenuScreen;
		revalidate();
		repaint();
	}

I still get the black screen after 1 click, the background image after the second.

I read up on the revalidate() method, and it seems to be fit for my cause, but somehow this doesn't work.
Debugging doesn't give me an answer either.

Aviras

Edited 5 Years Ago by Aviras: additional info

Add some printlns to show when the different events occur.

When does the getImage() method have the full image?

Edited 5 Years Ago by NormR1: n/a

I have played around with breakpoints and printlns.

At first I indeed thought it took some time to load the image, so I already loaded it in the constructor.

Then it's just a matter of copying the reference, which shoudn't take long.

However I don't know how to see when exactly the image has finished loading, if that is what you mean.

The g.drawImage() is reached the first time I click, the
mainTitleScreen has the same reference as the mainMenuScreen just before the repaint() in mousePressed(), however only a black screen is painted.

Edited 5 Years Ago by Aviras: n/a

Try using ImageIO vs getImage().

That seemed to do the trick, thanks a lot!

The ImageIO waits for the image to be fully loaded, which is how it should be.

But why doesn't getImage work if I already 'load' the image in the constructor,
possibly long before even using it ?

Considering the high speed with ImageIO, I don't see where the problem lies with getImage..

Try this with the getImage() method (comment out the ImageIO) :

MediaTracker mt = new MediaTracker(this);
      try{
         mt.addImage(titleScreen, 0);
         mt.waitForAll();
      }catch(Exception ex){ 
          ex.printStackTrace();
      }
Comments
Pretty much identical to what I was going to recommend :)

Using a MediaTracker is definitely a good idea: a MediaTracker will allow you to pre-load images on a loading screen and bypass any issues you may encounter with loading images on the fly - such as awkward display issues and not being able to get dimensional information on the image until after it has been drawn to the canvas.

It happens instantaneously. It works, and I understand why.

http://www.javacoffeebreak.com/articles/mediatracker/index.html has told me a thing or two about MediaTrackers, and it seems to be a handy tool, so thanks for bringing that up.

When getImage is called, a seperate Thread is created to load the Image ?

I've only just started GUI programming, using http://www.faqs.org/docs/javap/c6/s1.html chapter 6 and 7 as a foundation.

However efficient coding requires knowing what is going on at any time (at least on high-level), so I kind of want to get to the bottom of this..

yes when you call any accessing elements of an image the image is loaded at that time.

If you were to say create a new Image on "/myImage.jpg" and then call image.getWidth() it will return -1 until the image has been loaded.

Try this out in debug, call image.getWidth() and debug that line, if you call it again after a second or so (probably less, but it's a decent enough buffer) the image will finally be loaded.

It's an asynchronous process so that you don't go new Image("some massssssive image") and end up waiting a long time for it to display.

Using ImageBuffers and MediaTrackers are great alternatives since you can get the images immediately. These also allow for smarter handling of the images, which is really what most people want.

It is indeed an issue not to be overlooked, but things like MediaTrackers are great.

Thanks for answering everyone, you have been a great help, and I've learned some neat stuff.

This question has already been answered. Start a new discussion instead.