简体   繁体   English

Java swing动画看起来不稳定。如何让它看起来亲?

[英]Java swing animation looks choppy. How to make it look pro?

UPDATE: semicomplex animation + swing timer = trainwreck. 更新:semicomplex动画+摇摆计时器= trainwreck。 The ultimate source of the problems was the java timer, either the swing or utility version. 问题的最终根源是java计时器,无论是swing还是实用程序版本。 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/ . http://zetcode.com/tutorials/javagamestutorial/animation/ Also, adding Toolkit.getDefaultToolkit().sync() into the paintComponent() method noticeably helps. 此外,将Toolkit.getDefaultToolkit()。sync()添加到paintComponent()方法中会有显着的帮助。

I wrote some code that animated smoothly in an awt.Applet (but flickered), then I refactored it to java swing. 我写了一些代码,在awt.Applet中平滑动画(但是闪烁),然后我将它重构为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) 获取当前时间(保存在frameStartTime中)
  2. Do your frame 做你的框架
  3. Set the timer to go off in: interval - (newCurrentTime - frameStartTime) 将计时器设置为关闭: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),我认为你必须考虑JavaFX。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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