3

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.

Osh
  • 119
  • 1
  • 1
  • 8
  • I had added a bit of information regarding why your `setVisible()/revalidate()` calls never worked in this situation. Hopefully that will put some light on this whole thingy a bit more, as to why you getting this unexpected behaviour :-) – nIcE cOw Apr 07 '12 at 06:51
  • I had tried different combinations of setVisible(false) before than setting it back to true after the swingImage = tempImage; and also tried using .revalidate() before and after the setVisible(true). But I am beginning to believe it's the new JLabel(new ImageIcon(scaledImage) that's causing the problem... Still looking at it and trying to figure it out.... – Osh Apr 07 '12 at 06:58

1 Answers1

9

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 ?

Community
  • 1
  • 1
nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
  • 4
    Good approach; there's an example [here](http://sites.google.com/site/drjohnbmatthews/googleolympiad). – trashgod Apr 07 '12 at 04:19
  • Thankyou, for that :-), You did had an example for every situation, no doubt about that today, hehe :-) – nIcE cOw Apr 07 '12 at 04:33
  • 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! – Osh Apr 07 '12 at 07:29
  • or [Queue as another idea by @trashgod](http://stackoverflow.com/a/7944388/714968) +1 – mKorbel Apr 07 '12 at 07:46
  • 1
    @nIcE cOw not I have endless fortunas that [there are top 10](http://stackoverflow.com/tags/swing/topusers), that help me as we trying altogether to help another .... – mKorbel Apr 07 '12 at 08:03
  • 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 Apr 08 '12 at 00:20
  • 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. – Osh Apr 08 '12 at 05:02
  • 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. – nIcE cOw Apr 08 '12 at 05:08
  • 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? – Osh Apr 08 '12 at 23:54
  • 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](http://programmers.stackexchange.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](http://stackexchange.com/) and choose wisely :-) – nIcE cOw Apr 09 '12 at 03:36
  • 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. – Osh Apr 10 '12 at 01:33
  • 1
    Yes, true, if you find that the given answer stands well to your expectations, then you can mark it as correct, as explained [here](http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work), 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 :-) – nIcE cOw Apr 10 '12 at 03:54
  • @nIcE cOw - again, thank you for your direction. You have been a truly tremendous help!!!! – Osh Apr 11 '12 at 03:49
  • @Osh : Hehe, You are MOST Welcome and KEEP SMILING :-) – nIcE cOw Apr 11 '12 at 05:03