创建螺旋动画(延迟帮助)

时间:2014-04-05 05:50:08

标签: java animation delay sleep spiral

注意:我对Java很新,所以如果答案非常简单,请记住:)

我试图做的就是制作一个漂亮的螺旋动画,就像它在播放音乐时在Windows Media Player中显示的那样,或者像一个类似于Windows XP的屏幕保护程序的动画。

我试图弄清楚如何在创建一行之间创建延迟然后创建另一条线。

我希望程序以黑屏开始,每半秒左右,在制作一个很酷的螺旋动画之前,在一个稍微不同的位置添加一行

我确定可以使用Thread.Sleep()来做我想做的事情。我只是不知道该怎么做。

非常感谢任何帮助或建议! :d

我目前的代码图片:http://imgur.com/bsIqUOW

2 个答案:

答案 0 :(得分:2)

Swing是一个单线程环境。想要在常规基础上更改UI的状态时需要小心。您需要确保不以任何方式阻止事件调度线程,这样做可以防止处理任何新的绘制事件(以及其他事件),使您的UI看起来像挂起并确保您是否正在使用事件调度线程同步更新,以确保您不会冒任何竞争条件或其他线程问题的风险

仔细查看Concurrency in Swing了解更多详情。一种简单的方法是使用Swing Timer,例如......

enter image description here

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Spinner {

    public static void main(String[] args) {
        new Spinner();
    }

    public Spinner() {
        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 SpinnerPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class SpinnerPane extends JPanel {

        private float angle;

        public SpinnerPane() {
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    angle -= 5;
                    repaint();
                }
            });
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(40, 40);
        }

        protected Point calculateOutterPoint(float angel) {

            int radius = Math.min(getWidth(), getHeight());

            int x = Math.round(radius / 2);
            int y = Math.round(radius / 2);

            double rads = Math.toRadians((angel + 90));

            // This determins the length of tick as calculate from the center of
            // the circle.  The original code from which this derived allowed
            // for a varible length line from the center of the cirlce, we
            // actually want the opposite, so we calculate the outter limit first
            int fullLength = Math.round((radius / 2f)) - 4;

            // Calculate the outter point of the line
            int xPosy = Math.round((float) (x + Math.cos(rads) * fullLength));
            int yPosy = Math.round((float) (y - Math.sin(rads) * fullLength));

            return new Point(xPosy, yPosy);

        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

            int diameter = Math.min(getWidth(), getHeight());

            int x = (getWidth() - diameter) / 2;
            int y = (getHeight() - diameter) / 2;
            Point to = calculateOutterPoint(angle);
            g2d.drawLine(x + (diameter / 2), y + (diameter / 2), x + to.x, y + to.y);
            g2d.dispose();
        }

    }

}

使用类似的机制,我已经能够创建像......这样的等待动画。

enter image description here enter image description here

答案 1 :(得分:0)

您可以使用我的AnimationPanel课程并在其中进行绘图。此技术基于Active Rendering

代码:

// AnimationPanel.java
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

public abstract class AnimationPanel extends JPanel implements Runnable
{
  private static final long serialVersionUID = 6892533030374996243L;
  private static final int NO_DELAYS_PER_YIELD = 16;
  private static final int MAX_FRAME_SKIPS = 5;

  private static long fps = 30; // Frames Per Second.
  private static long period = 1000000L * (long) 1000.0 / fps;

  protected final int WIDTH;
  protected final int HEIGHT;
  private Thread animator;

  private volatile boolean running = false;
  private volatile boolean isWindowPaused = false;

  private Graphics dbg;
  private Image dbImage = null;

  public AnimationPanel(int width, int height)
  {
    WIDTH = width;
    HEIGHT = height;

    setPreferredSize(new Dimension(WIDTH, HEIGHT));

    setFocusable(true);
    requestFocus();
  }

  public void addNotify()
  {
    super.addNotify();
    startAnimation();
  }

  void startAnimation()
  {
    if (animator == null || !running)
    {
      animator = new Thread(this);
      animator.start();
    }
  }

  public void run()
  {
    long beforeTime, afterTime, timeDiff, sleepTime;
    long overSleepTime = 0L;
    int noDelays = 0;
    long excess = 0L;

    beforeTime = System.nanoTime();

    running = true;

    while (running)
    {
      requestFocus();
      animationUpdate();
      animationRender();
      paintScreen();

      afterTime = System.nanoTime();

      timeDiff = afterTime - beforeTime;
      sleepTime = (period - timeDiff) - overSleepTime;

      if (sleepTime > 0)
      {
        try
        {
          Thread.sleep(sleepTime / 1000000L);
        }
        catch (InterruptedException ignored)
        {
        }

        overSleepTime = (System.nanoTime() - afterTime - sleepTime);
      }
      else
      {
        excess -= sleepTime;
        overSleepTime = 0L;

        if (++noDelays >= NO_DELAYS_PER_YIELD)
        {
          Thread.yield();
          noDelays = 0;
        }
      }

      beforeTime = System.nanoTime();

      int skips = 0;

      while ((excess > period) && (skips < MAX_FRAME_SKIPS))
      {
        excess -= period;
        animationUpdate();
        skips++;
      }
    }

    stopAnimation();
    System.exit(0);
  }

  void stopAnimation()
  {
    running = false;
  }

  private void animationUpdate()
  {
    if (!isWindowPaused)
    {
      update();
    }
  }

  public abstract void update();

  private void animationRender()
  {
    if (dbImage == null)
    {
      dbImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);

      if (dbImage == null)
      {
        System.out.println("Image is null.");
        return;
      }
      else
      {
        dbg = dbImage.getGraphics();
      }
    }

    draw(dbg);
  }

  public abstract void draw(Graphics graphics);

  private void paintScreen()
  {
    Graphics g;

    try
    {
      g = this.getGraphics();
      if ((g != null) && (dbImage != null))
      {
        g.drawImage(dbImage, 0, 0, null);
      }

      Toolkit.getDefaultToolkit().sync();

      if (g != null)
      {
        g.dispose();
      }
    }
    catch (Exception e)
    {
      System.out.println("Graphics context error : " + e);
    }
  }

  public void setWindowPaused(boolean isPaused)
  {
    isWindowPaused = isPaused;
  }
}

如何使用:

AnimationPanelJPanel。在项目中复制粘贴此类 创建另一个类,并使其扩展AnimationPanel 覆盖update()中声明为abstract的draw()AnimationPanel方法。

update()方法内,您可以更改在此自定义类中声明的变量值。这些变量将是动画目的所需的变量,并且不断逐帧变换。

draw()内部方法中,使用您在自定义类中定义的变量执行所有自定义绘制。

如果您愿意,可以使用setWindowPaused()方法暂停动画。

演示:

// DemonstrationPanel.java
import java.awt.*;

public class DemonstrationPanel extends AnimationPanel
{
  private int red, green, blue;
  private int a, b, c, d;

  public DemonstrationPanel(int WIDTH, int HEIGHT)
  {
    super(WIDTH, HEIGHT);

    red = 100;
    green = blue = 5;

    a = 2;
    b = 500;
    c = 200;
    d = 5;
  }

  @Override
  public void update()
  {
    red += 5;
    red %= 255;

    blue += 1;
    blue %= 255;

    green += 10;
    green %= 255;

    a += 20;
    a %= HEIGHT;

    b += 1;
    b %= WIDTH;

    c += 15;
    c %= HEIGHT;

    d += 20;
    d %= WIDTH;
  }

  @Override
  public void draw(Graphics graphics)
  {
    // Uncomment the below two statements to just see
    // one line per frame of animation:

    // graphics.setColor(BACKGROUND_COLOR);
    // graphics.fillRect(0, 0, WIDTH, HEIGHT);

    graphics.setColor(new Color(red, green, blue));
    graphics.drawLine(b, c, d, a);
  }
}

这里有Demo课程:

// Demo.java
import javax.swing.*;
import java.awt.*;

public class Demo
{
  public Demo()
  {
    JFrame frame = new JFrame("Demo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(new DemonstrationPanel(800, 600));
    frame.setBackground(Color.BLACK);
    frame.setSize(800, 600);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }

  public static void main(String[] args)
  {
    SwingUtilities.invokeLater(new Runnable()
    {
      @Override
      public void run()
      {
        new Demo();
      }
    });
  }
}

您可以调整fps课程中AnimationPanel的值来更改动画的速度。