Updating an image contained in a JLabel - problems

23,036

Instead of creating a New Instance of the JLabel for each Image, simply use JLabel#setIcon(...) method of the JLabel to change the image.

A small sample program :

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SlideShow extends JPanel
{
    private int i = 0;
    private Timer timer;
    private JLabel images = new JLabel();
    private Icon[] icons = {UIManager.getIcon("OptionPane.informationIcon"),
                            UIManager.getIcon("OptionPane.errorIcon"),
                            UIManager.getIcon("OptionPane.warningIcon")};
    private ImageIcon pictures1, pictures2, pictures3, pictures4;
    private ActionListener action = new ActionListener()
    {
        public void actionPerformed(ActionEvent ae)
        {                       
            i++;
            System.out.println(i);

            if(i == 1)
            {
                pictures1 = new ImageIcon("image/caIcon.png");
                images.setIcon(icons[i - 1]);
                System.out.println("picture 1 should be displayed here");
            }
            if(i == 2)
            {
                pictures2 = new ImageIcon("image/Keyboard.png");
                images.setIcon(icons[i - 1]);   
                System.out.println("picture 2 should be displayed here");
            }
            if(i == 3)
            {
                pictures3 = new ImageIcon("image/ukIcon.png");
                images.setIcon(icons[i - 1]);
                System.out.println("picture 3 should be displayed here");  
            }
            if(i == 4)
            {
                pictures4 = new ImageIcon("image/Mouse.png");
                images.setIcon(icons[0]);   
                System.out.println("picture 4 should be displayed here");  
            }
            if(i == 5)
            {
                timer.stop();
                System.exit(0);
            }
            revalidate();
            repaint();
        }
    };

    public SlideShow()
    {
        JFrame frame = new JFrame("SLIDE SHOW");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);

        frame.getContentPane().add(this);

        add(images);

        frame.setSize(300, 300);
        frame.setVisible(true); 
        timer = new Timer(2000, action);    
        timer.start();  
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new SlideShow();
            }
        });
    }
}

Since you doing it with ImageIO, here is a good example related to that JLabel using ImageIO

Information relating to your case, as to what is happening :

Inside your createAndShowGUI() method you initializing your JLabel (swingImage), and you added that to your JPanel by virtue of which indirectly to the JFrame.

But now inside your updateImage() method, you are initializing a new JLabel, now it resides in some another memory location, by writing tempImage = new JLabel(new ImageIcon(scaledImage)); and after this you pointing your swingImage(JLabel) to point to this newly created JLabel, but this newly created JLabel was never added to the JPanel, at any point. Hence it will not be visible, even if you try revalidate()/repaint()/setVisible(...). Hence either you change the code for your updateImage(...) method to this :

protected void updateImage(String name) 
{
    BufferedImage image = null;
    Image scaledImage = null;
    JLabel tempImage;

    try
    {
        image = ImageIO.read(new File(name));
    } 
    catch (IOException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    // getScaledImage returns an Image that's been resized 
    // proportionally to my thumbnail constraints
    scaledImage = getScaledImage(image, THUMB_SIZE_X, THUMB_SIZE_Y);
    tempImage = new JLabel(new ImageIcon(scaledImage));
    rightPane.remove(swingImage);
    swingImage = tempImage;
    rightPane.add(swingImage, BorderLayout.PAGE_START);
    rightPane.revalidate();
    rightPane.repaint(); // required sometimes
}

Or else use JLabel.setIcon(...) as mentioned earlier :-)

UPDATED THE ANSWER

Here see how a New JLabel is placed at the position of the old one,

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class SlideShow extends JPanel
{
    private int i = 0;
    private Timer timer;
    private JLabel images = new JLabel();
    private Icon[] icons = {UIManager.getIcon("OptionPane.informationIcon"),
                            UIManager.getIcon("OptionPane.errorIcon"),
                            UIManager.getIcon("OptionPane.warningIcon")};
    private ActionListener action = new ActionListener()
    {
        public void actionPerformed(ActionEvent ae)
        {                       
            i++;
            System.out.println(i);          

            if(i == 4)
            {
                timer.stop();
                System.exit(0);
            }
            remove(images);
            JLabel temp = new JLabel(icons[i - 1]);
            images = temp;
            add(images);
            revalidate();
            repaint();
        }
    };

    private void createAndDisplayGUI()
    {
        JFrame frame = new JFrame("SLIDE SHOW");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationByPlatform(true);    

        this.setLayout(new FlowLayout(FlowLayout.LEFT));    

        add(images);

        frame.getContentPane().add(this, BorderLayout.CENTER);

        frame.setSize(300, 300);
        frame.setVisible(true); 
        timer = new Timer(2000, action);    
        timer.start();  
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new SlideShow().createAndDisplayGUI();
            }
        });
    }
}

And for your Question : Of the two options that I have tried, is one better than the other?

setIcon(...) has an edge over the other way, in the sense, you doesn't have to bother about revalidate()/repaint() thingy after adding/remove JLabel. Moreover, you don't need to remember the placement of your JLabel everytime, you add it. It remains at it's position, and you simply call the one method to change the image, with no strings attached and the work is done, without any headaches.

And for Question 2 : I had a bit of doubt, as to what is Array of Records ?

Share:
23,036
Osh
Author by

Osh

Not much to say, I've done some programming in the distant past. Schooling gave me COBOL, Pascal, C++, Modula-2, MVS Assember, etc... Yes, I'm dating myself... The last time I did any programming was with MS Visual Basic 6.0. Now, it's time I pick things up again, and Java was my choice. Primarily because of its platform independence. So with that, here goes.....

Updated on April 08, 2020

Comments

  • Osh
    Osh about 4 years

    The part of the application that I am currently having trouble getting to work is being able to scroll through and display a list of images, one at a time. I'm getting a directory from the user, spooling through all of the files in that directory, and then loading an array of just the jpegs and pngs. Next, I want to update a JLabel with the first image, and provide previous and next buttons to scroll through and display each image in turn. When I try to display the second image, it doesn't get updated... Here's what I've got so far:

    public class CreateGallery
    {
        private JLabel swingImage;
    

    The method that I'm using to update the image:

    protected void updateImage(String name) 
    {
        BufferedImage image = null;
        Image scaledImage = null;
        JLabel tempImage;
    
        try
        {
            image = ImageIO.read(new File(name));
        } catch (IOException e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    
        // getScaledImage returns an Image that's been resized proportionally to my thumbnail constraints
        scaledImage = getScaledImage(image, THUMB_SIZE_X, THUMB_SIZE_Y);
        tempImage = new JLabel(new ImageIcon(scaledImage));
        swingImage = tempImage;
    }
    

    Then in my createAndShowGUI method that puts the swingImage on...

    private void createAndShowGUI() 
    {
        //Create and set up the window.
        final JFrame frame = new JFrame();
    
        // Miscellaneous code in here - removed for brevity
    
        //  Create the Image Thumbnail swingImage and start up with a default image
        swingImage = new JLabel();
        String rootPath = new java.io.File("").getAbsolutePath();
        updateImage(rootPath + "/images/default.jpg");
    
        // Miscellaneous code in here - removed for brevity
    
        rightPane.add(swingImage, BorderLayout.PAGE_START);
        frame.add(rightPane, BorderLayout.LINE_END);
    
    public static void main(String[] args) 
    {
        SwingUtilities.invokeLater(new Runnable() 
        {
            public void run() 
            {
                UIManager.put("swing.boldMetal", Boolean.FALSE);
                new CreateGalleryXML().createAndShowGUI();
            }
        });
    }
    

    If you've gotten this far, the first image is my default.jpg, and once I get the directory and identify the first image in that directory, that's where it fails when I try to update the swingImage. Now, I've tried to swingImage.setVisible() and swingImage.revalidate() to try to force it to reload. I'm guessing it's my tempImage = new JLabel that's the root cause. But I'm not sure how to convert my BufferedImage or Image to a JLabel in order to just update swingImage.

  • trashgod
    trashgod about 12 years
    Good approach; there's an example here.
  • nIcE cOw
    nIcE cOw about 12 years
    Thankyou, for that :-), You did had an example for every situation, no doubt about that today, hehe :-)
  • Osh
    Osh about 12 years
    Thank you nIcE cOw! Your swingImage.setIcon(icon) solution worked... I want to look at your revamped updateImage method and see how that works, and also look at @trashgod's link as well. Once again, the both of you have helped me out!
  • mKorbel
    mKorbel about 12 years
  • mKorbel
    mKorbel about 12 years
    @nIcE cOw not I have endless fortunas that there are top 10, that help me as we trying altogether to help another ....
  • Osh
    Osh about 12 years
    Ok, the first test that I used was to just convert the scaledImage into an ImageIcon then swingImage.setIcon(icon); and that worked. Next, I tried your other example to remove the swingImage from the rightPane then add it back in and revalidate, but that blew up on me. I did not spend a lot of time on it, since I know the first option worked. I'm going to look at @trashgod's example and the other links in these comments as well. Question, of the two options that I have tried, is one better than the other? Question #2 - if I have an array of records, can one of those fields be the ImageIcon
  • Osh
    Osh about 12 years
    Ooops, sorry. I meant to say array of a class, but I know I answered that on my own. Which now opens up a ton of additional questions that I have. But I'm not certain this post is the right forum to ask. If it's not, please correct me. But going back, when I created a new object and the old object was "lost", what happened to it? Is it recoverable? If it isn't, how is that memory recovered? Is there a garbage collection process that I can call to recover any objects that are now orphaned? Please excuse my terminology if I'm not phrasing things with Java terms.
  • nIcE cOw
    nIcE cOw about 12 years
    Since you lost the reference to the said location, by pointing your variable to point to a new location, so you can not recover it, unless you know how to go deep into memory location using ASSEMBLY LANGUAGE. GARBAGE COLLECTION will take care of that object, which is not being referenced by any part of the program, so it will be released from the memory, when GARBAGE COLLECTION will run by the JVM. Moreover, there is no control on the GARBAGE COLLECTION by the developer, it happens at the sole discretion of the JVM.
  • Osh
    Osh about 12 years
    Ok, thanks @nIcE cOw!!! I do have more questions: 1 - Is it customary to "Answer Your Question" on here in order to close this dialog? 2 - Where is it appropriate to ask "Best Practice" types of questions? I have a bunch of those, but since they are more along the lines of "is it better to do something one way or a different way"... Like my question earlier about better to use setIcon() or remove then recreate the JLabel. Since you have been on here such a long time, and have such a high ranking, what is the appropriate standard that doesn't offend?
  • nIcE cOw
    nIcE cOw about 12 years
    Hehe, it depends on your luck sometimes, some ppl ask such questions here and they get answers, but sometimes the question is closed by ppl having good points :( Qestions on same terms get different reactions. Have a look at this Programmers.com, hope this page can give you some idea what sort of questions belong there. And for your " Is it customary to "Answer Your Question" on here in order to close this dialog? ", which dialog we talking about here, to be closed ? . Do have a look stackexchange and choose wisely :-)
  • Osh
    Osh about 12 years
    By the "Answer Your Question" and close this dialog, I really mean, is this like a tech support database? Where questions remain unanswered until you "Answer Your Question". So once it is answered, it now would appear as being a closed case. But I see what you mean by the stackexchange and choose wisely. Wow!!! I will browse around there though! I will also poke through the Programmers.com site and see if my questions belong there instead of here.
  • nIcE cOw
    nIcE cOw about 12 years
    Yes, true, if you find that the given answer stands well to your expectations, then you can mark it as correct, as explained here, or if the so called answer comes from your side, then you can post your own answer and mark it correct, both ways you will close the current thread, and help future visitors to get help from it :-)
  • Osh
    Osh about 12 years
    @nIcE cOw - again, thank you for your direction. You have been a truly tremendous help!!!!
  • nIcE cOw
    nIcE cOw about 12 years
    @Osh : Hehe, You are MOST Welcome and KEEP SMILING :-)