Search code examples
javaswinguser-interfaceactionlistenerjslider

GUI Animation: Slider Value between Action and Change classes?


My GUI frame comes up now but the slider value (speed) I get from my slider doesn't appear in my ActionLlistener class where I need use it as a delay in my timer. How do I bring that value over? The point is to run 12 images, like frames, at a speed that is determined by the value they slide on. Like if they slide to 12, there will be 12 milliseconds between each image.

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

public class SliderGUI {

    public static JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 100, 1);
    public static JLabel label = new JLabel ();
    public static JPanel panel = new JPanel();
    public static int delay;
    public static int speed;
    public static ImageIcon imageIcon;
    public static Timer timer = new Timer (delay, new SliderListener());

    public static void main(String[] args) {    
        JFrame frame = new JFrame("Legend Of Zelda");
        panel.setLayout(new GridLayout(5, 5, 5, 25));
        slider.setPaintLabels(true);
        slider.addChangeListener(new SliderListener());
        System.out.println (speed);
        timer.addActionListener (new SliderListener());

        frame.setVisible(true);
        frame.setResizable(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));

        panel.add(label);
        panel.add(slider);
        frame.setContentPane(panel);
        frame.pack();
    }

    private static class SliderListener implements ChangeListener, ActionListener {

        public void stateChanged(ChangeEvent e) {
            speed = slider.getValue();
            slider.setMajorTickSpacing(25);

        }

        public void actionPerformed (ActionEvent e) {
            for (int i = 1; i < 13; i++) {
                if (i == 12){
                    i = 1;
                }
                imageIcon = new ImageIcon(i + ".jpg");
                label.setIcon(imageIcon);
            }
            System.out.println ("Hi");
            timer = new Timer(speed, new SliderListener());
            timer.start();
        }
    }
}

Solution

  • Don't rely on static, it will blow up in your face...

    You are creating multiple instances SliderListener when you really should be only creating one and applying it to the JSlider (and in your case) the Timer.

    Having said that, I'd (personally) separate them...

    You're also creating a new Timer each time the ActionListener is called (so like a thousand times a second! So after 1 second, you could have 1001 Timers running!) all of which are going to be calling SliderListener at the same time, and because it's all linked via global variables...face in explosion...

    But I didn't actually see any where you were stating the Timer to start with...

    Runner

    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.imageio.ImageIO;
    import javax.swing.BorderFactory;
    import javax.swing.BoxLayout;
    import javax.swing.ImageIcon;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JSlider;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.event.ChangeEvent;
    import javax.swing.event.ChangeListener;
    
    public class SliderGUI {
    
        public static void main(String[] args) {
            new SliderGUI();
        }
    
        public SliderGUI() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            public JSlider slider = new JSlider(JSlider.HORIZONTAL, 10, 100, 10);
            public JLabel label;
            public int delay;
            public int speed;
            public ImageIcon imageIcon;
            public Timer timer;
    
            public TestPane() {
                setLayout(new GridLayout(5, 5, 5, 25));
                slider.setPaintLabels(true);
    
                label = new JLabel();
                try {
                    BufferedImage frameImage = ImageIO.read(getClass().getResource("/Run-0.png"));
                    label.setIcon(new ImageIcon(frameImage));
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
    
                SliderListener sliderListener = new SliderListener();
                timer = new Timer(delay, sliderListener);
                slider.addChangeListener(sliderListener);
                System.out.println(speed);
                timer.addActionListener(sliderListener);
    
                timer.start();
    
                setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
                setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
    
                add(label);
                add(slider);
            }
    
            private class SliderListener implements ChangeListener, ActionListener {
    
                public void stateChanged(ChangeEvent e) {
    
                    int value = slider.getValue();
                    timer.setDelay(value);
    
                }
    
                private int frame = 0;
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    System.out.println("Tick " + ((Timer) e.getSource()).getDelay());
                    try {
                        BufferedImage frameImage = ImageIO.read(getClass().getResource("/Run-" + frame + ".png"));
                        label.setIcon(new ImageIcon(frameImage));
                    } catch (IOException exp) {
                        exp.printStackTrace();
                    }
                    frame++;
                    if (frame > 11) {
                        frame = 0;
                    }
                }
            }
    
        }
    
    }
    

    Also, remember, a Timer is like a loop, each time the ActionListener is called, you should treat it as an iteration of a loop and update the state accordingly...