I want to load multiple images into a JPanel, and I prefer to load them on demand rather than all at once, especially since I'm using JScrollPane. Most of the images I load are from direct URLs, which I store in an array of Strings. I load them one by one in a for loop using my ImageLoader method
private void loadOnlineImages(String[] images, int maxWidth, int maxHeight) {
imagesPanel.removeAll();
imagesPanel.setLayout(new WrapLayout(FlowLayout.LEFT));
footerPanel.setTotalItems(images.length);
for (String image : images) {
ImageLoader onlineImageLoader =
new ImageLoader(imagesPanel, footerPanel, image, maxWidth, maxHeight);
onlineImageLoader.loadImage();
}
imagesPanel.revalidate();
imagesPanel.repaint();
}
I tried to use imagesPanel.isDisplayable and expected it to load the images only when they're visible in the JScrollPane, but it didn't work, and all the images still load simultaneously, which freezes the application. Most of the images I load are 10-50 KBs, so when I load 20 images, it doesn't freeze, but when I load 100, it freezes.
Here is the ImageLoader class used to load the images.
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URI;
import java.util.Iterator;
public class ImageLoader {
ProgressListener progressListener;
JPanel footerPanel;
JPanel imagesPanel;
String imageUrl;
int maxWidth;
int maxHeight;
public ImageLoader(JPanel imagesPanel, JPanel footerPanel, String imageUrl, int maxWidth, int maxHeight) {
this.imagesPanel = imagesPanel;
this.imageUrl = imageUrl;
this.maxWidth = maxWidth;
this.maxHeight = maxHeight;
this.footerPanel = footerPanel;
progressListener = new ProgressListener(footerPanel);
}
// Load the image only when it becomes visible
public void loadImage() {
new Thread(() -> {
try {
URI uri = URI.create(imageUrl);
ImageInputStream imageInputStream = ImageIO.createImageInputStream(uri.toURL().openStream());
Iterator<ImageReader> iterator = ImageIO.getImageReaders(imageInputStream);
if (iterator.hasNext()) {
ImageReader reader = iterator.next();
reader.setInput(imageInputStream);
reader.addIIOReadProgressListener(progressListener);
BufferedImage image = reader.read(reader.getMinIndex());
final ImageIcon icon = new ImageIcon(image);
// Check if the image is still required to be shown
if (imagesPanel.isDisplayable()) {
SwingUtilities.invokeLater(() -> {
JLabel imageLabel = new JLabel(IconScaler.createScaledIcon(icon, maxWidth, maxHeight));
imagesPanel.add(imageLabel);
imagesPanel.revalidate();
imagesPanel.repaint();
});
}
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
Thank you so much in advance for your assistance!