Wololo
Wololo

Reputation: 861

Making a slideshow program

I am trying to make a slideshow program. I want the next slide to appear when I click (There are only two slides not, but I will add more once the errors r sorted out). The code compiles fine. But when i click, nothing happens. What could possibly go wrong?

package project;

import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;

public class Frame extends JFrame{

Frame() {
    setLayout(new BorderLayout());
    ImageIcon slide = new ImageIcon("E:\\Books\\Computer\\Java\\Introduction to Java Programming\\exercise9e\\image\\slide0.jpg");
    JLabel slidesLabel = new JLabel(slide);
    add(slidesLabel,BorderLayout.CENTER);
    slidesLabel.addMouseListener(new ClickListener());
}

public void nextSlide() {
    ImageIcon slide = new ImageIcon("E:\\Books\\Computer\\Java\\Introduction to Java Programming\\exercise9e\\image\\slide1.jpg");
    JLabel slidesLabel = new JLabel(slide);
    add(slidesLabel,BorderLayout.CENTER);
    System.out.println("x");
}

public static void main(String args[]) {
    Frame frame = new Frame();
    frame.setSize(800,600);
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
    frame.setVisible(true);
}

public class ClickListener extends MouseAdapter {
    @Override
    public void mouseClicked(MouseEvent e) {
        nextSlide();
    }
}

}

Upvotes: 2

Views: 4901

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347194

So, the "main" problem is BorderLayout will only manage a single component within any of the five available locations it manages.

Adding another component into the position tends to cause issues, where the component that was first added won't be displayed, or in your case, will remain and could interfere with the new component

"A" solution would be to re-use the same JLabel for each slide, simply supply a new value for the icon property (or in this example, the text property)

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Frame extends JFrame {

    private JLabel slidesLabel = new JLabel("Apple");
    public Frame() {
        setLayout(new BorderLayout());
        add(slidesLabel, BorderLayout.CENTER);
        slidesLabel.addMouseListener(new ClickListener());
    }

    public void nextSlide() {
        slidesLabel.setText("Banana");
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                Frame frame = new Frame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ClickListener extends MouseAdapter {

        @Override
        public void mouseClicked(MouseEvent e) {
            nextSlide();
        }
    }

}

This approach would allow you to place each icon into an array and simply have a counter which determines which slide is current, so when you click for the next slide, you simply increment the counter, get the next value from the array and apply it to the label

A better (and more appropriate) solution would be to actually use a CardLayout, see How to Use CardLayout for more details

With icons...

SlideShow

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Frame extends JFrame {

    private JLabel slidesLabel = new JLabel();
    private Icon[] icons;
    private int currentSlide = -1;

    public Frame() {
        try {
            // Personally, I'd use File#listFiles to list all the
            // images in a directory, but that might be consider
            // using our initiative...
            icons = new Icon[]{
                new ImageIcon(ImageIO.read(new File("..."))),
                new ImageIcon(ImageIO.read(new File("..."))),
                new ImageIcon(ImageIO.read(new File("...")))
            };
            slidesLabel.setVerticalAlignment(JLabel.CENTER);
            slidesLabel.setHorizontalAlignment(JLabel.CENTER);
            setLayout(new BorderLayout());
            add(slidesLabel, BorderLayout.CENTER);
            slidesLabel.addMouseListener(new ClickListener());
            nextSlide();
        } catch (IOException exp) {
            exp.printStackTrace();
        }
    }

    public void nextSlide() {
        if (currentSlide < icons.length - 1) {
            currentSlide++;
            slidesLabel.setIcon(icons[currentSlide]);
        }
    }

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                Frame frame = new Frame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ClickListener extends MouseAdapter {

        @Override
        public void mouseClicked(MouseEvent e) {
            nextSlide();
        }
    }

}

Why simply adding components to a BorderLayout is bad...

BadLayout

All I did was when nextSlide was called, create a new JLabel assign it the next icon and add it to the Frame (which is using a BorderLayout) and then re-sized the frame. Because the labels are transparent, they remain visible...

This is why you shouldn't simply add new components to a BorderLayout, but, in your case, simply update the properties of the existing JLabel to meet the changing needs.

Upvotes: 4

Related Questions