注意:我对Java很新,所以如果答案非常简单,请记住:)
我试图做的就是制作一个漂亮的螺旋动画,就像它在播放音乐时在Windows Media Player中显示的那样,或者像一个类似于Windows XP的屏幕保护程序的动画。
我试图弄清楚如何在创建一行之间创建延迟然后创建另一条线。
我希望程序以黑屏开始,每半秒左右,在制作一个很酷的螺旋动画之前,在一个稍微不同的位置添加一行
我确定可以使用Thread.Sleep()来做我想做的事情。我只是不知道该怎么做。
非常感谢任何帮助或建议! :d
我目前的代码图片:http://imgur.com/bsIqUOW
答案 0 :(得分:2)
Swing是一个单线程环境。想要在常规基础上更改UI的状态时需要小心。您需要确保不以任何方式阻止事件调度线程,这样做可以防止处理任何新的绘制事件(以及其他事件),使您的UI看起来像挂起并确保您是否正在使用事件调度线程同步更新,以确保您不会冒任何竞争条件或其他线程问题的风险
仔细查看Concurrency in Swing了解更多详情。一种简单的方法是使用Swing Timer,例如......
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();
}
}
}
使用类似的机制,我已经能够创建像......这样的等待动画。
答案 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;
}
}
AnimationPanel
是JPanel
。在项目中复制粘贴此类
创建另一个类,并使其扩展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
的值来更改动画的速度。