3

I'm trying to create an animation (spinning text) by repeatedly changing the icon on a JLabel. The issue is the images are not of the same size, and when they are bigger than the size of the first image, they are clipped.

One way around this is to setPreferredSize for the JLabel so that all images fit - but I imagine there must be a way dinamically resize the JPanel containing the JLabel?

In the code bellow I've also tried removing the JLabel alltogether, creating a new one and then adding the new one, but to the same effect.

public class AnimationPanelv2 extends JPanel{

private JButton start = new JButton("Start Animation");
private JLabel img = new JLabel();
private JTextField animSpeed = new JTextField(10);
private JTextField filePrefix = new JTextField(10);
private JTextField noOfImg = new JTextField(10);
private JTextField audioFile = new JTextField(10);
private Timer timer;
private AudioClip clip;
private ArrayList<ImageIcon> icon = new ArrayList<>();
private int step=0;


public AnimationPanelv2() {

    //button is for starting the animation
    start.addActionListener(new Animatie());

    this.setLayout(new BorderLayout());
    add(start, BorderLayout.NORTH);

    //showing the label with the first frame
    Class metaObj = this.getClass();
    URL url = metaObj.getResource("/image/L1.gif");

    img.setIcon(new ImageIcon(url));
//      img.setPreferredSize(new Dimension(500,550));
    add(img, BorderLayout.CENTER);

    //control panel
    JPanel controls = new JPanel(new GridLayout(4,2));

    controls.setBorder(new TitledBorder("Enter information for animation"));

    controls.add(new JLabel("Animation speed in ms"));
    controls.add(animSpeed);
    controls.add(new JLabel("Image file prefix"));
    controls.add(filePrefix);
    controls.add(new JLabel("Number of images"));
    controls.add(noOfImg);
    controls.add(new JLabel("Audio file"));
    controls.add(audioFile);

    //
    add(controls, BorderLayout.SOUTH);
}
private class TimerAnimation implements ActionListener {

    public void actionPerformed(ActionEvent e) {

        remove(img);

        img = new JLabel(icon.get(step++));
        img.setVisible(true);
        add(img, BorderLayout.CENTER);

//          img.revalidate();
//          img.repaint();



        validate();
        repaint();
        updateUI();
        if (step==Integer.parseInt(noOfImg.getText())) step=0;
    }

}
private class Animatie implements ActionListener {

    public void actionPerformed(ActionEvent e) {

        //getting data from the text fields
        int ms = Integer.parseInt(animSpeed.getText());
        String s = filePrefix.getText();
        int nr = Integer.parseInt(noOfImg.getText());
        String audioFilePath = audioFile.getText();

        // clip
        Class metaObj = this.getClass();
        URL url = metaObj.getResource("/audio/"+audioFilePath);
        clip = Applet.newAudioClip(url);

        //image loading
        for (int i=1; i<=nr; i++){
            url = metaObj.getResource("/image/"+s+i+".gif");
            System.out.println("/image/"+s+i+".gif");
            icon.add(new ImageIcon(url));
        }

        //timer
        timer = new Timer(ms, new TimerAnimation());
        timer.start();
        clip.loop();
    }
}

public static void main(String[] args) {

    JFrame jf = new JFrame("This class test");
    jf.setLocationRelativeTo(null);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    jf.add(new AnimationPanelv2());
    jf.pack();
    jf.setVisible(true);
}
}

This whole panel will be used in an applet.

This is a screenshot: http://screencast.com/t/UmqQFZHJVy

The images that are supposed to be the frames, should be located in an /images/ sub-directory and if the user enters n for the number of frames and F for the image prefix, then the files are F1, F2, and so on, to Fn (GIFs). The sound file should be in an /audio/ sub-directory, and the entire file name is given by the user.

David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
Mihai Ocneanu
  • 693
  • 6
  • 17
  • How should we test this if we have to find out the names of your pictures etc and replace them – David Kroukamp Dec 18 '12 at 12:48
  • @DavidKroukamp, I've included details about the files, in order to have as much info as needed. – Mihai Ocneanu Dec 18 '12 at 13:26
  • Typically I'd `pack()` the TLC (e.g. on change of PLAF) as shown [here](http://stackoverflow.com/questions/5621338/how-to-add-jtable-in-jpanel/5630271#5630271). For better help sooner, post an [SSCCE](http://sscce.org/). – Andrew Thompson Dec 18 '12 at 13:46
  • @AndrewThompson - I also thought about something similar to pack(), but this is a JPanel not a JFrame. If the animation would be taking place in a JFrame, then I imagine a pack() call after the label change would do the trick, but it is not the case :( – Mihai Ocneanu Dec 18 '12 at 14:14
  • 1
    In that case try `parent.revalidate()`. *"but this is a JPanel not a JFrame"* OK, and what is the TLC displaying the panel? – Andrew Thompson Dec 18 '12 at 22:00
  • @AndrewThompson - thanks for the tip. Following your suggestion I tried SwingUtilities.windowForComponent(this).pack() and SwingUtilities.getRoot(this).revalidate() but to no result. Right now, for testing purposes, inside main I'm adding the panel to a JFrame, but the panel should be used in an JApplet. That's why I didn't extend a JFrame from the beginning. Perhaps I am going the wrong way about this? – Mihai Ocneanu Dec 19 '12 at 08:31
  • *"Following your suggestion I tried.."* Try posting an SSCCE (another of my suggestions). – Andrew Thompson Dec 19 '12 at 11:48

2 Answers2

3

You can try to create list of JLabels for each image, add them to a panel with CardLayout and swap cards.

StanislavL
  • 56,971
  • 9
  • 68
  • 98
  • Thanks for the suggestion, but unfortunately I get the same behavior. Once created, the panel keeps that same size, unless manually re-sized. – Mihai Ocneanu Dec 18 '12 at 12:26
3

Okay well a JLabel should size automatically to its given content, so to solve JPanel issue, simply override getPreferredSize() of JPanel containing the JLabel and return Dimensions according to the JLabel size.

public class MyPanel extends JPanel {
JLabel label=...;


    @Override
    public Dimension getPreferredSize() {
        return new Dimension(label.getWidth(),label.getHeight());
    }

}

also dont forget when you change Icon of JLabel call revalidate() and repaint() on JPanel instance in order for size changes to refelect.

zhujik
  • 6,514
  • 2
  • 36
  • 43
David Kroukamp
  • 36,155
  • 13
  • 81
  • 138
  • +1 but I think the list of labels should be iterated to get max size – StanislavL Dec 18 '12 at 13:34
  • I've just tried overriding getPreferredSize as you suggested, but the panel does not resize(even tried with hard values). I've also tried manually calling setPreferredSize(getPreferredSize()), setSize(getPreferredSize()), setSize(hard values) after replacing the label. Also, just before re-adding the new label I've tried setting its Size and preferredSize to that of the new Icon, but none of this worked. – Mihai Ocneanu Dec 18 '12 at 13:36
  • @OcneanuMihai I cannot see how this will not work, it might be something else, I will test as soon as I get time to create images etc – David Kroukamp Dec 18 '12 at 14:01
  • @StanislavL would that really be a good thing? getting the maximum size of a picture, thus if there is any simple collision detection a smaller image will now be seen as intersecting another when in actual fact they are not but according to the JPanel size it does. unless I misunderstood what you meant by maximum size – David Kroukamp Dec 18 '12 at 14:03
  • @DavidKroukamp IMHO it's better to have one size to avoid layout jumping. Or even scale the pictures to have equal size. getScaledInstance() I mean – StanislavL Dec 18 '12 at 15:25
  • @StanislavL +1 agreed. but in that case I would recommend OP go with game logic using extension of Shape r Rectangl etc, thus no Layout switching. for example: http://stackoverflow.com/questions/13825515/java-rectangle-collision-detection-confusion/13827649#13827649 – David Kroukamp Dec 18 '12 at 15:50