Java waits for a component to be colored

I am trying to create a program in Java that will display many images one by one, changing the frame size for each of them. I am expanding a JPanel to display an image as follows:

public class ImagePanel extends JPanel{ String filename; Image image; boolean loaded = false; ImagePanel(){} ImagePanel(String filename){ loadImage(filename); } public void paintComponent(Graphics g){ super.paintComponent(g); if(image != null && loaded){ g.drawImage(image, 0, 0, this); }else{ g.drawString("Image read error", 10, getHeight() - 10); } } public void loadImage(String filename){ loaded = false; ImageIcon icon = new ImageIcon(filename); image = icon.getImage(); int w = image.getWidth(this); int h = image.getHeight(this); if(w != -1 && w != 0 && h != -1 && h != 0){ setPreferredSize(new Dimension(w, h)); loaded = true; }else{ setPreferredSize(new Dimension(300, 300)); } } 

}

Then in the event flow, I do the main work:

  SwingUtilities.invokeLater(new Runnable(){ @Override public void run(){ createGUI(); } }); 

In createGUI () I am looking at a set of images:

  ImagePanel imgPan = new ImagePanel(); add(imgPan); for(File file : files){ if(file.isFile()){ System.out.println(file.getAbsolutePath()); imgPan.loadImage(file.getAbsolutePath()); pack(); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 

The problem is that my program resizes correctly, so the images load correctly, but do not display anything. If I show only 1 image, it works and works for the last image. I think the problem is that Thread.sleep () is called before the image is finished drawing.

How can I wait until my ImagePanel finishes drawing and starts to wait after that? Or is there another way to solve the problem?

Thanks! Leonty

+4
source share
3 answers

All your code is executed in Thread Dispatch Thread. This actually makes all user interaction sleep, as the Dispatch event stream is responsible for all user interaction - both input (events) and output (painting).

You need your expectation to happen outside of the EDT. You need to know how to execute events on and off the EDT. You do this by creating a new Runnable and then calling new Thread(runnable) to execute it with EDT or SwingUtilities.invokeLater(runnable) to execute it on EDT. All interaction with Swing components must occur on the EDT, since Swing objects are not thread safe. All sleep, waiting, file access, network access, database access, or anything else that may be blocked for indefinite periods of time, must occur with EDT.

There are many stack overflow questions related to Thread Dispatch Thread. I recommend that you look through them to find more information and code samples to do what you want to do differently.

+4
source

Instead of forcing the sleep thread to use a timer and trigger the next image as an event.

+1
source

It sounds like you want the images to be displayed one after the other when they are loading (that is, like on a web page), is this correct? If this is the case, you will not get this effect with your current code, because your user interface will not be updated until all images are downloaded, this is because you upload images to EDT (Thread Dispatch Thread), which is the same stream. I will make a picture. Painting takes place "when there is time", which in this case means that after loading all the images.

To solve your problem, I suggest you create a subclass of the SwingWorker class, for example:

 public class MyImageLoader extends SwingWorker<Void, String> { // Is executed in background thread, EDT can meanwhile load and paint images @Override protected Void doInBackground() throws Exception { for(File file : files) { if(file.isFile()) // Maybe some more check to see if it an image { publish(file.getAbsolutePath()); Thread.sleep(500); } } } // Executed on EDT @Override protected void process(List<String> filePaths) { for(String path : filePaths) { // Load ImageIcon to UI } } } 
+1
source

All Articles