Program freezes during Thread.sleep() and with Timer

混江龙づ霸主 提交于 2019-12-17 02:26:29

问题


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);
}

回答1:


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.*;

public class TimerTime extends JFrame implements ActionListener
{
    JLabel timeLabel;

    public TimerTime()
    {
        timeLabel = new JLabel( new Date().toString() );
        getContentPane().add(timeLabel, BorderLayout.NORTH);
    }

    public void actionPerformed(ActionEvent e)
    {
        timeLabel.setText( new Date().toString() );
    }

    public static void main(String[] args)
    {
        TimerTime frame = new TimerTime();
        frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
        frame.pack();
        frame.setVisible(true);

        int time = 1000;
        javax.swing.Timer timer = new javax.swing.Timer(time, frame);
        timer.setInitialDelay(1);
        timer.start();
    }
}



回答2:


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




回答3:


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);
    }
}


来源:https://stackoverflow.com/questions/7816585/program-freezes-during-thread-sleep-and-with-timer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!