repaint() needs to be called twice for Image
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
Aviras
Junior Poster in Training
82 posts since Jul 2008
Reputation Points: 24
Solved Threads: 8
mKorbel
Veteran Poster
1,141 posts since Feb 2011
Reputation Points: 480
Solved Threads: 224
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
Aviras
Junior Poster in Training
82 posts since Jul 2008
Reputation Points: 24
Solved Threads: 8
Add some printlns to show when the different events occur.
When does the getImage() method have the full image?
NormR1
Posting Expert
6,677 posts since Jun 2010
Reputation Points: 1,138
Solved Threads: 656
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.
Aviras
Junior Poster in Training
82 posts since Jul 2008
Reputation Points: 24
Solved Threads: 8
Try using ImageIO vs getImage().
NormR1
Posting Expert
6,677 posts since Jun 2010
Reputation Points: 1,138
Solved Threads: 656
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..
Aviras
Junior Poster in Training
82 posts since Jul 2008
Reputation Points: 24
Solved Threads: 8
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();
}
NormR1
Posting Expert
6,677 posts since Jun 2010
Reputation Points: 1,138
Solved Threads: 656
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..
Aviras
Junior Poster in Training
82 posts since Jul 2008
Reputation Points: 24
Solved Threads: 8
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.
Aviras
Junior Poster in Training
82 posts since Jul 2008
Reputation Points: 24
Solved Threads: 8