Java Swing 动画看起来断断续续.如何让它看起来很专业? [英] Java swing animation looks choppy. How to make it look pro?

查看:44
本文介绍了Java Swing 动画看起来断断续续.如何让它看起来很专业?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

更新:半复杂动画 + 摆动计时器 = 火车残骸.问题的最终根源是 java 计时器,无论是 Swing 还是实用程序版本.它们不可靠,尤其是在跨操作系统比较性能时.通过实现普通线程,该程序在所有系统上运行非常流畅.http://zetcode.com/tutorials/javagamestutorial/animation/.此外,将 Toolkit.getDefaultToolkit().sync() 添加到paintComponent() 方法中也有明显帮助.

我在 awt.Applet 中编写了一些动画流畅的代码(但闪烁),然后我将其重构为 java swing.现在它不闪烁,但看起来断断续续.我弄乱了计时器,但这不起作用.任何有关平滑地为摆动组件设置动画的提示或建议将不胜感激.<预><代码>导入 java.util.Random;导入 java.util.ArrayList;导入 java.awt.event.;导入 java.awt.;导入 javax.swing.*;//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

公共类 Ball 扩展 JApplet{

public static void main(String[] args) {SwingUtilities.invokeLater(new Runnable() {公共无效运行(){JFrame frame = new JFrame();frame.setTitle("所以球滚了");frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);initContainer(框架);框架.pack();frame.setVisible(true);}});}公共静态无效initContainer(容器容器){GraphicsPanel graphicsPanel = new GraphicsPanel();MainPanel mainPanel = new MainPanel(graphicsPanel);容器.添加(主面板);graphicsPanel.startTimer();}@覆盖公共无效初始化(){initContainer(这个);}

}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////类 MainPanel 扩展 JPanel {JLabel label = new JLabel("粒子");图形面板 gPanel;

 public MainPanel(GraphicsPanel gPanel){this.gPanel = gPanel;添加(gPanel);添加(标签);}

}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////class GraphicsPanel 扩展 JPanel 实现 MouseListener {

 private ArrayListballArr = new ArrayList();私人字符串状态=s";//"s"=螺旋,"p"=粒子私有整数速度=10;//~20赫兹私人定时器定时器;公共图形面板(){System.out.println("gpanel 回显");setPreferredSize(new Dimension(500,500));timer = new Timer(speed, new TimerListener());addMouseListener(this);}public void startTimer(){定时器开始();}@覆盖公共无效paintComponent(图形g){super.paintComponent(g);对于(粒子 b:ballArr){g.setColor(b.getColor());g.fillOval(b.getXCoor(),b.getYCoor(),b.getTheSize(),b.getTheSize());}}public void mousePressed(MouseEvent e) {ballArr.add(new Particle(e.getX(), e.getY(), state));}public void mouseReleased(MouseEvent e) {}public void mouseEntered(MouseEvent e){}public void mouseExited(MouseEvent e){}public void mouseClicked(MouseEvent e) {}类 TimerListener 实现 ActionListener {public void actionPerformed(ActionEvent e){for(粒子b:ballArr)b.移动();设置背景(颜色.白色);重绘();}}

}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////类粒子{私有静态 int instanceCount;{{instanceCount++;}}私有整数 z = 11,t=1,u=1;私有整数[] RGB = 新整数[3];private int[] randomizeColor = new int[3];私人双半径,theta;私有整数 x,y,centerX,centerY,大小,螺旋方向 = 1,ballSizeLowerBound, ballSizeUpperBound,半径下界,半径上界,鼠标输入X,鼠标输入Y,半径XMultiplier,radiusYMultiplier;私人颜色颜色;私有字符串状态;私人随机随机=新随机();//////////////////////////////////////////////////////////////////////////公共粒子(int x,int y,int centerX,int centerY,int半径,int theta,int大小,颜色颜色){this.x=x;this.y=y;this.centerX=centerX;this.centerY=centerY;this.radius=radius;this.theta=theta;this.size=size;this.color=color;}

public Particle(int mouseInputX, int mouseInputY, String state){this.mouseInputX=mouseInputX;this.mouseInputY=mouseInputY;this.state=state;//随机颜色RGB[0] = random.nextInt(252);RGB[1] = random.nextInt(252);RGB[2] = random.nextInt(252);randomizeColor[0] = 1+random.nextInt(3);randomizeColor[0] = 1+random.nextInt(3);randomizeColor[0] = 1+random.nextInt(3);centerX=鼠标输入X;centerY=鼠标输入Y;if (state.equals("s")){//设置螺旋状态ballSizeLowerBound=5;ballSizeUpperBound=18;半径下界=0;半径上限=50;半径X乘数=1;半径Y乘数=1;}if (state.equals("p")){//设置粒子状态ballSizeLowerBound = 15;ballSizeUpperBound =20 + random.nextInt(15);半径下界 = 5;radiusUpperBound = 15+ random.nextInt(34);radiusXMultiplier=1 + random.nextInt(3);radiusYMultiplier=1 + random.nextInt(3);}大小 = ballSizeUpperBound-1;//球的大小半径 = radiusUpperBound-1;if (instanceCount %2 == 0)//交替螺旋方向螺旋方向=-螺旋方向;}//////////////////////////////////////////////////////////////////////////public int getXCoor(){return centerX+x*spiralDirection;}public int getYCoor(){return centerY+y;}public int getTheSize(){返回大小;}public Color getColor(){返回颜色;}/////////////////////////////////////////////////////////////////////////空移动(){//螺旋:dr/dt在边界上变化if (radius > radiusUpperBound || radius

}

解决方案

不要设置固定间隔计时器.将计时器设置为关闭一次——在处理程序中

  1. 获取当前时间(保存在 frameStartTime 中)
  2. 做你的框架
  3. 将计时器设置为在以下时间关闭:间隔 - (newCurrentTime - frameStartTime)

应该更流畅.如果你想成为真正的专业人士(并留在 Java 中),我认为你必须考虑 JavaFX.

UPDATE: semicomplex animation + swing timer = trainwreck. The ultimate source of the problems was the java timer, either the swing or utility version. They are unreliable, especially when performance is compared across operating systems. By implementing a run-of-the-mill thread, the program runs very smoothly on all systems. http://zetcode.com/tutorials/javagamestutorial/animation/. Also, adding Toolkit.getDefaultToolkit().sync() into the paintComponent() method noticeably helps.

I wrote some code that animated smoothly in an awt.Applet (but flickered), then I refactored it to java swing. Now it doesn't flicker but it looks choppy. I've messed with the timer but that doesn't work. Any tips or suggestions for smoothly animating swing components would be greatly appreciated.


import java.util.Random;
import java.util.ArrayList;
import java.awt.event.;
import java.awt.;
import javax.swing.*;
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////

public class Ball extends JApplet{

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            JFrame frame = new JFrame();
            frame.setTitle("And so the ball rolls");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            initContainer(frame);
            frame.pack();
            frame.setVisible(true);
        }
    });
}
public static void initContainer(Container container){

   GraphicsPanel graphicsPanel = new GraphicsPanel();
   MainPanel mainPanel = new MainPanel(graphicsPanel);
   container.add(mainPanel);
   graphicsPanel.startTimer();

}

@Override
public void init(){
    initContainer(this);
}

} /////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// class MainPanel extends JPanel { JLabel label = new JLabel("Particles"); GraphicsPanel gPanel;

    public MainPanel(GraphicsPanel gPanel){
        this.gPanel = gPanel;
        add(gPanel);
        add(label);
    }

} /////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// class GraphicsPanel extends JPanel implements MouseListener {

    private ArrayList<Particle> ballArr = new ArrayList<Particle>();
    private String state="s";         //"s"=spiral, "p"=particle
    private int speed=10;             //~20 Hz
    private Timer timer;

    public GraphicsPanel(){
        System.out.println("echo from gpanel");
        setPreferredSize(new Dimension(500,500));
        timer = new Timer(speed, new TimerListener());
        addMouseListener(this);
    }

    public void startTimer(){
        timer.start();
    }

    @Override
    public void paintComponent(Graphics g){

        super.paintComponent(g);
         for (Particle b: ballArr){
              g.setColor(b.getColor());
              g.fillOval(b.getXCoor(),b.getYCoor(),
                         b.getTheSize(),b.getTheSize());
         }
    }

    public void mousePressed(MouseEvent e) {
        ballArr.add(new Particle(e.getX(), e.getY(), state));
    }
    public void mouseReleased(MouseEvent e) {}
    public void mouseEntered(MouseEvent e){}
    public void mouseExited(MouseEvent e){}
    public void mouseClicked(MouseEvent e) {}

    class TimerListener implements ActionListener {
        public void actionPerformed(ActionEvent e){
             for (Particle b: ballArr)
                 b.move();
             setBackground(Color.WHITE);
             repaint();

        }
    }

}

////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// class Particle { private static int instanceCount; {{instanceCount++;}} private int z = 11, t=1, u=1; private int[] RGB = new int[3]; private int[] randomizeColor = new int[3]; private double radius, theta; private int x, y, centerX, centerY, size, spiralDirection=1, ballSizeLowerBound, ballSizeUpperBound, radiusLowerBound, radiusUpperBound, mouseInputX, mouseInputY, radiusXMultiplier, radiusYMultiplier; private Color color; private String state; private Random random = new Random(); /////////////////////////////////////////////////////////////////////////// public Particle(int x, int y, int centerX, int centerY, int radius, int theta, int size, Color color){ this.x=x;this.y=y;this.centerX=centerX;this.centerY=centerY; this.radius=radius;this.theta=theta;this.size=size;this.color=color; }

public Particle(int mouseInputX, int mouseInputY, String state){ this.mouseInputX=mouseInputX; this.mouseInputY=mouseInputY; this.state=state; //randomize color RGB[0] = random.nextInt(252); RGB[1] = random.nextInt(252); RGB[2] = random.nextInt(252); randomizeColor[0] = 1+random.nextInt(3); randomizeColor[0] = 1+random.nextInt(3); randomizeColor[0] = 1+random.nextInt(3); centerX=mouseInputX; centerY=mouseInputY; if (state.equals("s")){ //setup spiral state ballSizeLowerBound=5; ballSizeUpperBound=18; radiusLowerBound=0; radiusUpperBound=50; radiusXMultiplier=1; radiusYMultiplier=1; } if (state.equals("p")){ //setup particle state ballSizeLowerBound = 15; ballSizeUpperBound =20 + random.nextInt(15); radiusLowerBound = 5; radiusUpperBound = 15+ random.nextInt(34); radiusXMultiplier=1 + random.nextInt(3); radiusYMultiplier=1 + random.nextInt(3); } size = ballSizeUpperBound-1; //ball size radius = radiusUpperBound-1; if (instanceCount %2 == 0) // alternate spiral direction spiralDirection=-spiralDirection; } /////////////////////////////////////////////////////////////////////////// public int getXCoor(){return centerX+x*spiralDirection;} public int getYCoor(){return centerY+y;} public int getTheSize(){return size;} public Color getColor(){return color;} ////////////////////////////////////////////////////////////////////////// void move(){ //spiral: dr/dt changes at bounds if (radius > radiusUpperBound || radius < radiusLowerBound) u = -u; //spiral shape formula: parametric equation for the //polar equation radius = theta x = (int) (radius * radiusXMultiplier * Math.cos(theta)); y = (int) (radius * radiusYMultiplier * Math.sin(theta)); radius += .1*u; theta += .1; //ball size formula if (size == ballSizeUpperBound || size == ballSizeLowerBound) t = -t; size += t; //ball colors change for (int i = 0; i < RGB.length; i++) if (RGB[i] >= 250 || RGB[i] <= 4) randomizeColor[i] = -randomizeColor[i]; RGB[0]+= randomizeColor[0]; RGB[1]+= randomizeColor[1]; RGB[2]+= randomizeColor[2]; color = new Color(RGB[0],RGB[1],RGB[2]); }

}

解决方案

Don't set a constant interval timer. Set the timer to go off once -- in the handler

  1. Get the current time (save in frameStartTime)
  2. Do your frame
  3. Set the timer to go off in: interval - (newCurrentTime - frameStartTime)

Should be smoother. If you want to go really pro (and stay in Java), I think you have to consider JavaFX.

这篇关于Java Swing 动画看起来断断续续.如何让它看起来很专业?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆