Search code examples
javaswingjlabelimageicon

JLabel.setIcon() does not work as desired


I am writing this Google Map component for Java Swing. I only need to use Google static map. I want the map to update based on a button action which reads user input, but the image which wrapped in a JLabel just does not update.

I cache the static map in mapCache.jpg and set the JLabel mapContent's icon to it every time the ActionListener fires. But it just does not work. mapCache.jpg is updated on my system, but it just does not update in the program. I tried to remove imageicon or remove mapContent from JScrollPane, but neither of these worked. I suspect that JVM caches the image file. If so, how can I clear the cache?

Here's what's inside my class:

private static final long serialVersionUID = 2243575060653389810L;
private String latlong;
private int zoomLevel;
private JLabel mapContent;
private ImageIcon mapImage;

public MapComponent(float lat, float lon, int zoom){
    latlong = validateLatlong(lat,lon);
    zoomLevel = validateZoomLevel(zoom);
    queryMap();

    setLayout(new BorderLayout());
    mapImage = new ImageIcon("mapCache.jpg");
    mapContent = new JLabel(mapImage);
    JScrollPane sp = new JScrollPane(mapContent);
    add(sp, BorderLayout.CENTER);

    JPanel inputPane = new JPanel();
    JLabel latLabel = new JLabel("Latitude: ");
    final JTextField latText = new JTextField(""+lat);
    JLabel longLabel = new JLabel("Longitude: ");
    final JTextField longText = new JTextField(""+lon);
    JLabel zoomLabel = new JLabel("Zoom Level: ");
    final JTextField zoomText = new JTextField(""+zoomLevel);
    zoomText.setPreferredSize(new Dimension(20,15));
    JButton mapGo = new JButton("Go");
    mapGo.addActionListener(new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent e) {
            try{
                queryMap(Float.parseFloat(latText.getText()), Float.parseFloat(longText.getText()), Integer.parseInt(zoomText.getText()));
                mapImage.setImage(new ImageIcon("mapCache.jpg").getImage());
                mapContent.setIcon(null);
                mapContent.setIcon(mapImage);  // Doesn't work!
            }
            catch(Exception ex){
                ex.printStackTrace();
            }
        }
    });
    inputPane.add(latLabel);
    inputPane.add(latText);
    inputPane.add(longLabel);
    inputPane.add(longText);
    inputPane.add(zoomLabel);
    inputPane.add(zoomText);
    inputPane.add(mapGo);
    add(inputPane, BorderLayout.PAGE_END);

    setVisible(true);
}

private void queryMap(){
    try {
        String imageUrl = "http://maps.google.com/staticmap?center="+latlong+"&zoom="+zoomLevel+
                "&size=1000x750&maptype=roadmap&markers="+latlong+
                "&key=ABQIAAAAgb5KEVTm54vkPcAkU9xOvBR30EG5jFWfUzfYJTWEkWk2p04CHxTGDNV791-cU95kOnweeZ0SsURYSA&format=jpg";
        System.out.println(imageUrl);
        String destinationFile = "mapCache.jpg";
        URL url = new URL(imageUrl);
        InputStream is = url.openStream();
        OutputStream os = new FileOutputStream(destinationFile);
        byte[] b = new byte[2048];
        int length;
        while ((length = is.read(b)) != -1) {
            os.write(b, 0, length);
        }
        is.close();
        os.flush();
        os.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

}

public void queryMap(float lat, float lon, int zoom){
    latlong = validateLatlong(lat,lon);
    zoomLevel = validateZoomLevel(zoom);
    queryMap();
}

private String validateLatlong(float lat, float lon){
    lat = Math.min(lat, 90);
    lat = Math.max(lat, -90);
    lon = Math.min(lon, 90);
    lon = Math.max(lon, -90);
    return lat+","+lon;
}

private int validateZoomLevel(int zoom){
    zoom = Math.min(zoom, 15);
    zoom = Math.max(zoom, 1);
    return zoom;
}

Solution

  • ImageIcon, uses a Image as it's backing source, the Image caches it's image data in memory. You need to flush the image data before you try reapplying it to the label

    mapContent.setIcon(null);
    
    mapImage.getImage().flush();
    mapContent.setIcon(mapImage);  // Doesn't work! - Does now :)
    

    I'd also recommend that you have a look at The try-with-resources Statement and handle your resources better, for example...

    try (InputStream is = url.openStream(); OutputStream os = new FileOutputStream(destinationFile)) {
        byte[] b = new byte[2048];
        int length;
        while ((length = is.read(b)) != -1) {
            os.write(b, 0, length);
        }
    }