Reputation: 41
So I have never used Swing Worker at all, but I heard it was a good way to load images because it allows for images to be processed in the background from what I believe. In the process of trying to implement it I ran into a problem where the image isn't draw. I don't have any errors, but the screen just seems white. Can anybody take a look at my code and tell me where it's going wrong?
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
public class Screen extends JPanel{
//Screen Vairables
public static JFrame frame = new JFrame("Soul Voyage");
public Dimension size = new Dimension((int)Toolkit.getDefaultToolkit().getScreenSize().width,(int)Toolkit.getDefaultToolkit().getScreenSize().height);
Graphics draw;
public Screen(){
//Screen Creation
frame.setSize(size);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setVisible(true);
//Other
}
@Override
public void paintComponent(Graphics g){
draw = g;
super.paintComponent(g);
new ImageLoader().execute();
g.dispose();
}
public static void main(String[] args) {
Screen s = new Screen();
frame.add(s);
}
class ImageLoader extends SwingWorker{
private ImageIcon image;
@Override
protected Icon doInBackground() throws IOException {
Image picture = ImageIO.read(new URL("Background.jpg"));
image = new ImageIcon(picture);
image.paintIcon(frame, draw, size.width, size.height);
return image;
}
}
}
Upvotes: 2
Views: 2420
Reputation: 168815
never used Swing Worker at all, but I heard it was a good way to load images because it allows for images to be processed in the background
Java could read images asynchronously since the Toolkit
in Java 1.1.
If added to an ImageObserver
such as a JPanel
, a repaint()
will be invoked when there is more of the image to draw. Load progress can be monitored using a MediaTracker
.
Upvotes: 2
Reputation: 347184
SwingWorker
runs in the background, in a separate Thread
, so doing something like...
new ImageLoader().execute();
Basically says, do this and I will continue running...It won't wait for worker to complete.
You really shouldn't be loading images in paintXxx
methods anyway...and don't dispose
of resources you did not explicitly create (ie g.dispose()
is a bad idea) and draw = g;
worries me, you shouldn't be trying to maintain a reference to any Graphics
context you did not explicitly create...
Instead, you should pass some kind of callback to the SwingWorker
, so when it's done, it knows who to notify.
Now, one of the reasons to use a SwingWorker
is because it has functionality to allow you to more easily synchronise the background process with the Event Dispatching Thread, making it safer to interact with the UI without fear of generating dirty paints or dead locked threads :P
For example...
public interface ImageConsumer {
public void imageLoaded(BufferedImage img);
}
public class Screen extends JPanel implements ImageConsumer {
/*...*/
private BufferedImage img;
public Screen(){
new ImageLoader(this).execute();
}
/*...*/
public void imageLoaded(BufferedImage img) {
this.img = img;
repaint();
}
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
protected class ImageLoader extends SwingWorker<BufferedImage, BufferedImage> {
private ImageConsumer consumer;
public ImageLoader(ImageConsumer consumer) {
this.consumer = consumer;
}
@Override
protected BufferedImage doInBackground() throws IOException {
BufferedImage picture = ImageIO.read(new URL("Background.jpg"));
return picture;
}
protected void done() {
try {
BufferedImage img = get();
consumer.imageLoaded(img);
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
}
Upvotes: 4