Vito Valov
Vito Valov

Reputation: 1795

How to simulate video within ImageIcon?

I have JToggleButton and this method capturing events:

tgl_playMouseClicked(java.awt.event.MouseEvent evt) {                                             
            new Thread() {
                public void run() {
                    int i = 0;
                    String outputName = null;
                    while ((i <= 99)) {
                        ImageIcon imgThisImg = new ImageIcon("images/" + outputName + i + ".png");
                        lbl_image.setIcon(imgThisImg);
                        i++;
                    }
                    tgl_play.setSelected(!tgl_play.isSelected());

                }
            }.start();
}

I try to simulate video by reading and showing single images in imageIcon. When I fist time click on JToggleButton, all is ok. Video is running. But when I press again, nothing happens. The event is captured as prints are displayed in output, but no refresh on ImageIcon.

I use thread there in order to be able to set some delay between frames.

What's wrong? Help me please

Upvotes: 0

Views: 315

Answers (1)

Guillaume Polet
Guillaume Polet

Reputation: 47617

I think that one of your best shot is to use javax.swing.Timer to pace your "video". This will ensure that you are doing everything properly with Swing EDT.

(If the millisecond is not sufficient, then I would take a look at: java.util.concurrent.Executors.newScheduledThreadPool(int) and java.util.concurrent.ScheduledThreadPoolExecutor.scheduleAtFixedRate(Runnable, long, long, TimeUnit) and add Runnable's that immediately call all their code in SwingUtilities.invokeLater())

Here I made a small demo example with a list of images displaying a growing and shrinking circle (the images are created on the fly with some JPanel but this is just for the demo).

import java.awt.Color;
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UnsupportedLookAndFeelException;

public class TestAnimation {
    private static final int NB_OF_IMAGES = 50;
    private static final int NB_OF_IMAGES_PER_SECOND = 25;
    private static final int WIDTH = 300;
    private static final int HEIGHT = 300;

    protected void initUI() {
        final JFrame frame = new JFrame(TestAnimation.class.getSimpleName());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(false);
        // the label on which I will set images
        final JLabel label = new JLabel();
        // By adding to the frame, it is set as the central component of the 
        // BorderLayout of the JFrame. Eventually, the label will have the size of the content pane
        frame.add(label);
        frame.setSize(WIDTH, HEIGHT);
        // Creating a list of images (just for demo purposes)
        final List<Image> images = new ArrayList<Image>(NB_OF_IMAGES);
        for (int i = 0; i < NB_OF_IMAGES; i++) {
            CirclePanel circle = new CirclePanel(WIDTH / 2, WIDTH / 2, 2 * WIDTH * (NB_OF_IMAGES / 2 - Math.abs(i - NB_OF_IMAGES / 2))
                    / NB_OF_IMAGES);
            circle.setSize(WIDTH, HEIGHT);
            BufferedImage image = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration()
                    .createCompatibleImage(WIDTH, HEIGHT, BufferedImage.TRANSLUCENT);
            circle.print(image.getGraphics());
            images.add(image);
        }
        // Here is the timer logic
        Timer t = new Timer(1000 / NB_OF_IMAGES_PER_SECOND, new ActionListener() {
            private int i = 0;

            @Override
            public void actionPerformed(ActionEvent e) {
                if (i == images.size()) {
                    i = 0;
                }
                label.setIcon(new ImageIcon(images.get(i++)));
            }
        });
        frame.setVisible(true);
        t.start();
    }

    // Simple class that draws a red circle centered on x,y and given radius
    public static class CirclePanel extends JPanel {

        private int x;
        private int y;
        private int radius;

        public CirclePanel(int x, int y, int radius) {
            super();
            this.x = x;
            this.y = y;
            this.radius = radius;
            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(Color.RED);
            g.drawArc(x - radius / 2, y - radius / 2, radius, radius, 0, 360);
        }
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException,
            UnsupportedLookAndFeelException {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new TestAnimation().initUI();
            }
        });
    }
}

Upvotes: 4

Related Questions