简体   繁体   中英

Program freezes during Thread.sleep() and with Timer

Original question:

This method is supposed to change the image being displayed on a JFrame gradually into another image. However, without some way to slow it down, it just seems to change from one image to the new image. In order to slow it down, I put in a Thread.sleep(1000) so the changes wouldn't happen instantly. However, with this line in there, my program freezes completely. No error message, no nothing. Can anyone please help me out? Suggest a better method to slow it down, or how this can be fixed.

For clarification: int k is the number of gradual steps in the change. k = 1 would be an instant change. Anything greater would be gradual changes. int l meanwhile controls the ratio of how much of each image is displayed.

public void morphImg(int width, int height, BufferedImage morphImage, int k) {
    //creates new image from two images of same size
    BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    for (int i = 0; i < width; i++) {
        for (int j = 0; j < height; j++) {
            //get color from original image
            Color c = new Color(image.getRGB(i, j));

            //get colors from morph image
            Color c2 = new Color(morphImage.getRGB(i, j));

            for (int l = 1; l <= k; l++) {
                //gets colors at different stages
                int r = ((k-l)*c.getRed()/k) + (l*c2.getRed()/k);
                int g = ((k-l)*c.getGreen()/k) + (l*c2.getGreen()/k);
                int b = ((k-l)*c.getBlue()/k) + (l*c2.getBlue()/k);   
                Color newColor = new Color(r, g, b);
                //set colors of new image to average of the two images
                image2.setRGB(i, j, newColor.getRGB());

                //display new image
                try {
                    imageLabel.setIcon(new ImageIcon(image2));
                    Thread.sleep(1000);
                }
                catch (InterruptedException e){
                    System.out.println("Exception caught.");
                }
            }
        }
    }

    //sets modified image as "original" for further manipulation
    setImage(image2);
}

UPDATED CODE: Using a Timer also causes the program to freeze...Am I not using it right?

public void morphImg(int width, int height, BufferedImage morphImage, int k) {
    //creates new image from two images of same size
    final BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    for (int l = 1; l <= k; l++) {
        for (int i = 0; i < width; i++) {
            for (int j = 0; j < height; j++) {
                //get color from original image
                Color c = new Color(image.getRGB(i, j));

                //get colors from morph image
                Color c2 = new Color(morphImage.getRGB(i, j));

                //gets colors at different stages
                int r = ((k-l)*c.getRed()/k) + (l*c2.getRed()/k);
                int g = ((k-l)*c.getGreen()/k) + (l*c2.getGreen()/k);
                int b = ((k-l)*c.getBlue()/k) + (l*c2.getBlue()/k);   
                Color newColor = new Color(r, g, b);

                //set colors of new image to average of the two images
                image2.setRGB(i, j, newColor.getRGB());
                //display new image

                imageLabel.setIcon(new ImageIcon(image2));
                final Timer t = new Timer(500,null);
                t.setInitialDelay(500);
                t.start();
            }
        }
    }

    //sets modified image as "original" for further manipulation
    setImage(image2);
}

Never use Thread.sleep() when code is executing on the Event Dispatch Thread.

Instead you should use a Swing Timer to schedule your animation.

See the sections from the Swing tutorial on:

  1. Concurrency in Swing
  2. How to Use Timers

Or if you don't want to use a Timer, then you can use a SwingWorker (as described in the tutorial on concurrency) and then just publish() the image after you change it. Then you can use a Thread.sleep() since the SwingWorker doesn't execute on the EDT.

Simple Timer example:

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

public class TimerTime extends JPanel implements ActionListener
{
    private JLabel timeLabel;
    private int count = 0;

    public TimerTime()
    {
        timeLabel = new JLabel( new Date().toString() );
        add( timeLabel );

        Timer timer = new Timer(1000, this);
        timer.setInitialDelay(1);
        timer.start();
    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        //  Update the time

        timeLabel.setText( new Date().toString() );
        count++;

        //  Stop after 10 events have been generated

        if (count == 10)
        {
            Timer timer = (Timer)e.getSource();
            timer.stop();
            System.out.println( "Timer stopped" );
        }
    }

    private static void createAndShowGUI()
    {
        JFrame frame = new JFrame("TimerTime");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new TimerTime() );
        frame.setLocationByPlatform( true );
        frame.pack();
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater( () -> createAndShowGUI() );
    }
}

The loop over k should be the outermost loop. Right now you are calling Thread.sleep k*width*height times.

If the intention is to show progressive animation of the morph effect, below is the test code I did without using Timer or Thread.sleep() , using the latest morph code given by OP:

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.JApplet;
import javax.swing.JFrame;


class MorphComponent extends Component {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private BufferedImage bi;
    private URL imageSrc1;
    private URL imageSrc2;     
    public MorphComponent(URL imageSrc1, URL imageSrc2) {
        this.imageSrc1 = imageSrc1;
        this.imageSrc2 = imageSrc2;     
        try {
            BufferedImage img1 = ImageIO.read(imageSrc1);
            //BufferedImage img2 = ImageIO.read(imageSrc2);
            int w = img1.getWidth(null);
            int h = img1.getHeight(null);
            bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
            Graphics g = bi.getGraphics();
            g.drawImage(img1, 0, 0, null);

        } catch (IOException e) {
            System.out.println("Image could not be read");
            System.exit(1);
        }
    }

    public Dimension getPreferredSize() {
        return new Dimension(bi.getWidth(null), bi.getHeight(null));
    }


    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        g2d.setColor(Color.white);
        g2d.fillRect(0,0, getWidth(), getHeight());
        try {
            BufferedImage img1 = ImageIO.read(imageSrc1);
            BufferedImage img2 = ImageIO.read(imageSrc2);
            int w = img1.getWidth(null);
            int h = img1.getHeight(null);        
            bi = morphImg(g, img1, img2, w, h, 10);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private long start = System.currentTimeMillis();

    public BufferedImage morphImg(Graphics gp, BufferedImage originalImage, BufferedImage morphImage, int width, int height, int k) {
        //creates new image from two images of same size
        final BufferedImage image2 = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int l = 1; l <= k; l++) {
            for (int i = 0; i < width; i++) {
                for (int j = 0; j < height; j++) {
                    long elapsed = System.currentTimeMillis() - start;
                    //get color from original image
                    Color c = new Color(originalImage.getRGB(i, j));

                    //get colors from morph image
                    Color c2 = new Color(morphImage.getRGB(i, j));

                    //gets colors at different stages
                    int r = ((k-l)*c.getRed()/k) + (l*c2.getRed()/k);
                    int g = ((k-l)*c.getGreen()/k) + (l*c2.getGreen()/k);
                    int b = ((k-l)*c.getBlue()/k) + (l*c2.getBlue()/k);   
                    Color newColor = new Color(r, g, b);

                    //set colors of new image to average of the two images
                    image2.setRGB(i, j, newColor.getRGB());

                    if( elapsed > 100 ) {
                        gp.drawImage(image2, 0, 0, null);
                        start = System.currentTimeMillis();
                        repaint();
                    }

                }
            }
        }
        return image2;
    }

}

public class MorphImageApplet extends JApplet {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    static String imageFileName1 = "image_1.jpg";
    static String imageFileName2 = "image_2.jpg";
    private URL imageSrc1;
    private URL imageSrc2;

    public MorphImageApplet () {
    }

    public MorphImageApplet (URL imageSrc1, URL imageSrc2) {
        this.imageSrc1 = imageSrc1;
        this.imageSrc2 = imageSrc2;
    }

    public void init() {
        try {
            imageSrc1 = new URL(getCodeBase(), imageFileName1);
            imageSrc2 = new URL(getCodeBase(), imageFileName2);
        } catch (MalformedURLException e) {
        }
        buildUI();
    }

    public void buildUI() {
        final MorphComponent st = new MorphComponent(imageSrc1, imageSrc2);
        add("Center", st);
    }

    public static void main(String s[]) {
        JFrame f = new JFrame("See Through Image");
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {System.exit(0);}
        });
        URL imageSrc1 = null;
        URL imageSrc2 = null;
        try {
             imageSrc1 = ((new File(imageFileName1)).toURI()).toURL();
             imageSrc2 = ((new File(imageFileName2)).toURI()).toURL();
        } catch (MalformedURLException e) {
        }
        MorphImageApplet sta = new MorphImageApplet(imageSrc1, imageSrc2);
        sta.buildUI();
        f.add("Center", sta);
        f.pack();
        f.setVisible(true);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM