When drawing a BufferedImage , the transition image does not display. I am trying to create a game in which when the user wins, it displays a loading transitional screen and then proceeds to the img2 screen. I want to create a 1 or 2 second delay to make it seem as though the second level is in the process of loading however when I add thread.sleep it delays it but does not display the transition image, instead, it just jumps straight toimg2. I have tried creating separate flags,methods and increasing the time but nothing seems to work!
Below is the paintComponenetmethod (I have tried separating into separate methods):
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(img, 0, 0, this);
if (win1 == true) {
try {
Thread.sleep(1000);
} catch (Exception exc) {
}
g2d.drawImage(transition, 0, 0, this);
try {
Thread.sleep(1000);
} catch (Exception exc) {
}
g2d.drawImage(img2, 0, 0, this);
}
}
}
An explanation would be very helpful as well!
All painting is done on the Event Dispatch Thread.
When you invoke Thread.sleep() in the paintComponent() method the GUI can't repaint itself until all the code is finished executing which means only the last image will ultimately get painted as the two paint requests will be combined into one. Read the section from the Swing tutorial on Concurrency for more information.
Don't use Thread.sleep() in a painting method.
The better solution is to not even do custom painting. Instead you can just use a JLabel and change the Icon of the label.
Then you can use use a Swing Timer to schedule the animation. So you would set the Icon and then set the Timer to fire in 2 seconds. When the Timer fires you reset the Icon of the label.
Related
I have a program that has multiple layers, in the bottom layer I have a JPanel that I have put a background image on. On top of this I have a JLayeredPane that has some draggable components. My problem is that when the user have uploaded a background image the draggable components are really lagging, my guess is that it's because of that swing is repainting the background image al the time when dragging. My question is if its anyway to make sure the image is not repainting all the time?
My code where I paint the image looks like this:
if (this.getLoadedBackgroundImage() != null) {
try {
BufferedImage bufferedImage = ImageIO.read(this.getLoadedBackgroundImage());
Image bImage = bufferedImage.getScaledInstance(this.getWidth() - 5 - jPanel6.getWidth() -5, this.getHeight() - jPanel2.getHeight() - jPanel3.getHeight() - tabPanel.getHeight(), Image.SCALE_FAST);
graphics2d.drawImage(bImage, 5, jPanel2.getHeight() + tabPanel.getHeight()+5, null);
} catch (IOException ex) {
Logger.getLogger(MainViewLayeredPane.class.getName()).log(Level.SEVERE, null, ex);
}
}
Don't load or resize the image the paintComponent method, these are expensive operations, instead, pre-cache it and only paint the cached version
So Im a beginner experimenting with ImageIO. Can someone tell me why im getting this pixelated-incomplete sprite?
Here's the code
public BufferedImage getImage(String location)
{
try
{
File file = new File(location);
image = ImageIO.read(file);
}
catch (IOException e)
{
System.err.println("It don't work!!");
e.printStackTrace();
}
return image;
}
And Im using this method to display it
public void paint(Graphics g)
{
g.drawImage(getImage("Numbers/icon0.png"), 0, 0, 32, 32, null);
repaint();
}
And here's what it gives me
If you want to display the first (single) cell of your sprite, you probably meant to write:
g.drawImage(getImage("Numbers/icon0.png").getSubimage(0, 0, 32, 32), 0, 0, null);
Notice the getSubimage(x, y, w, h) part, to get a single cell.
If you wanted to draw the entire sprite sheet, you could use:
g.drawImage(getImage("Numbers/icon0.png"), 0, 0, null);
Your original code will draw the entire sprite sheet, rescaled to 32x32.
PS: You should probably not invoke repaint() from the paint method, as that will create an endless repaint loop. If you want your component to repaint, use some kind of timer that repaints your component at fixed intervals.
PPS: You should probably not do I/O (ie. read the image) inside the paint method, because any I/O operation may take time and make your UI sluggish and unresponsive. It's also unnecessary, as the sprite sheet does not change every time you repaint. Instead, read the image up front, and only draw it in the paint method.
Currently I have a JPanel with its paintComponent overridden with lots of image processing based on various states. When an event occurs (infrequent) many of the states change and the images that are drawn change. It doesn't seem the best way to keep doing all the processing every time the paintComponent is it possible to do something like when an event occurs draw everything to a Graphics2D instance and then merge this with the paintComponent one? Is this also the best way to do it?
As MadProgrammer suggested, storing rendered output can help you.
When the event that might change the image occurs, you can draw stuff to a BufferedImage like following.
private BufferedImage renderedImage;
public void triggerEvent(int width, int height) {
this.renderedImage = new BufferedImage(width, height, TYPE_INT_ARGB);
Graphics2D g = this.renderedImage.createGraphics();
// Paint things on g.
}
#Override
public void paintComponent(Graphics g) {
g.drawImage(this.renderedImage, 0, 0, this);
}
Hope this helps.
I have a panel on which I want to draw stuff.
Painting on it when it is beeing created is no problem.
canvas = new Panel() {
public void paint(Graphics g) {
g.setColor(Color.WHITE);
g.drawLine(0, 0, 10, 10);
}
};
But then I want to draw on it during runtime.
By instinct, I've created something like this:
Graphics g = canvas.getGraphics();
g.setColor(Color.GREEN);
g.drawLine(10, 10, 20, 20);
canvas.paint(g);
Sadly, this doesn't work.
This is probably a simple question but I cannot find a satisfying result by searching.
So how can I do what I want to do?
Sorry for the question above.
I just added the paint code on a button click event and it works.
It just doesn't work on the windowOpened event of the parent frame.
Any ideas why?
The problem is that the paint() method can be called at any time whenever the window system (or OS) decides that the particular graphical component needs to be repainted on screen. This may happen at any moment (most often when resizing, moving, switching windows, etc). To see how often it happens just add a log message at the beginning of paint() method. If you paint something on canvas just once it's very likely that it's painted, but then another repaint request comes from OS/window system and your green line gets "overdrawn" by object's paint() .
So the answer is that any custom painting should be done in paint(). You can add extra attributes to your subclass (eg. boolean drawGreenLine), check it in paint() and take any appropriate action, eg:
class MyPanel extends JPanel {
boolean drawGreenLine;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.WHITE);
g.drawLine(0, 0, 10, 10);
if (drawGreenLine) {
g.setColor(Color.GREEN);
g.drawLine(10, 10, 20, 20);
}
}
};
EDIT: As suggested by #MadProgrammer the example has been changed to override paintComponent(). This way the component is only responsible for drawing itself (and not any children or borders).
try g.dispose() to release the GraphicsContext's ressources
Im trying to slowly paint a rectangle using two calls of .fillrect method with Thread.sleep call between each method. What is happening is that the sleep method is getting called before the rectangle is initialised, so it appears that the rectange has already been painted. I just want to paint part of the rectange, pause for five seconds and then paint antother part.
Here is my code -
public void paint(Graphics g, int w, int h) {
g.drawRect(0, 0, w - 1, h - 1);
g.fillRect(0, 0, 10, h-1);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
g.fillRect(0, 0, 50, h-1);
}
Thanks
It is always a very BAD idea to cause an event thread to block, no matter what the platform.
What you should be doing is defining variables somewhere that store the current extent of the area you want painted. Update those variables on a separate thread (you can block that thread all you want) and call the repaint() method to schedule a repaint whenever you update the variables.