重绘方法因短暂延迟而停止工作

时间:2016-01-29 06:17:48

标签: java swing

我试图创建一个简单的面板,其中二维球在上下弹跳。我无法让它工作,因为出于某种原因,我不能每秒多次调用重绘方法。设计基本上是有一个可以给出的对象"一个冲动"使用方法move()。每次调用evaluatePosition方法时,将通过已经过的时间,速度和加速度计算当前位置。该面板的代码是:

public class Display extends JPanel {
  private MovableObject object = new MovableObject(new Ellipse2D.Double(5,5,50,50));
  private static final int DELAY = 1000;

  public Display(){
    object.move(50,50);
    Timer timer = new Timer(DELAY, new ActionListener(){
      @Override
      public void actionPerformed(ActionEvent e){
        object.evaluatePosition();
        repaint();
      }
    });
    timer.start();
  }
}

@Override
public void paintComponent(Graphics g){
  super.paintComponent(g);
  Graphics2D g2 = (Graphics2D)g;
  g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  g.drawOval((int)object.getPosition().getX(), (int)object.getPosition.getY()
     (int)object.getShape().getWidth(), object.getShape().getHeight());
}

此代码适用于DELAY = 1000但不适用于DELAY = 100或DELAY = 10,依此类推。我在这里阅读了一些示例代码,但它们在我看来就像我已经做过的那样。那么为什么我的代码不起作用?

编辑(2016-01-30): 因为它似乎确实是一个性能问题,所以这里是MovableObject的代码(我只是认为它是无关紧要的,你可能会看到原因):

public class MovableObject {
  // I would really like to use Shape instead of Ellipse2D so that 
  // objects of any shape can be created
  private Ellipse2D.Double shape; 
  private Point position;
  // Vector is my own class. I want to have some easy vector addition and
  // multiplication and magnitude methods
  private Vector velocity = new Vector(0, 0);
  private Vector acceleration = new Vector(0, 0); 
  private Date lastEvaluation = new Date();

  public MovableObject(Ellipse2D.Double objectShape){
    shape = objectShape;
  }

  public void evaluatePosition(){
    Date currentTime = new Date();
    long deltaTInS = (currentTime.getTime()-lastEvaluation.getTime())/1000;
    // s = s_0 + v*t + 0.5*a*t^2
    position = new Point((int)position.getX()+ (int)(velocity.getX()*deltaTInS) + (int)(0.5*acceleration.getX()*deltaTInS*deltaTInS),
                        (int)position.getY()+ (int)(velocity.getY()*deltaTInS) + (int)(0.5*acceleration.getY()*deltaTInS*deltaTInS));
    lastEvaluation = currentTime;
  }
}

public void move(Vector vector){
    velocity = velocity.add(vector);
    evaluatePosition(); 
}

public Point getPosition(){
    return position;
}

public Ellipse2D.Double getShape(){
    return shape;
}

我的移动方法不会改变位置而是改变速度。 请注意我刚刚将形状Object从Shape更改为Ellipse2D,以便测试我的代码是否因为附加代码而出现性能问题。因此,如果您认为这比它需要的更复杂:我实际上想要添加一些复杂性,以便MovableObject可以具有任何形状子类的形状。我已经看到很多代码对我来说似乎更复杂并且渲染速度很快。所以我想知道这有什么不对(除了它只是渲染一个椭圆有点太复杂了。)

1 个答案:

答案 0 :(得分:2)

好的,这是一个简单的例子,基于您离开的上下文代码片段,它似乎没有任何问题。它具有由简单滑块控制的可变速度......

Bounce

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class Display extends JPanel {

    public static void main(String[] args) {
        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 Display());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private MovableObject object = new MovableObject(new Ellipse2D.Double(5, 5, 50, 50));
    private int delay = 40;

    private Timer timer = new Timer(40, new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            object.evaluatePosition(getSize());
            repaint();
        }
    });

    private JSlider slider = new JSlider(5, 1000);

    public Display() {
        object.move(50, 50);

        slider = new JSlider(5, 1000);
        slider.setSnapToTicks(true);
        slider.setMajorTickSpacing(10);
        slider.setMinorTickSpacing(5);
        setLayout(new BorderLayout());
        add(slider, BorderLayout.SOUTH);

        // This is simply designed to put an artificate delay between the
        // change listener and the time the update takes place, the intention
        // is to stop it from pausing the "main" timer...
        Timer delay = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (timer != null) {
                    timer.stop();
                }
                timer.setDelay(slider.getValue());
                timer.start();
            }
        });

        slider.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                delay.restart();
                repaint();
            }
        });

        slider.setValue(40);
    }

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

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g.create();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.draw(object.getTranslatedShape());
        FontMetrics fm = g2.getFontMetrics();
        String text = Integer.toString(slider.getValue());
        g2.drawString(text, 0, fm.getAscent());
        g2.dispose();
    }

    public class MovableObject {

        private Shape shape;
        private Point location;

        private int xDelta, yDelta;

        public MovableObject(Shape shape) {
            this.shape = shape;
            location = shape.getBounds().getLocation();
            Random rnd = new Random();
            xDelta = rnd.nextInt(8);
            yDelta = rnd.nextInt(8);

            if (rnd.nextBoolean()) {
                xDelta *= -1;
            }
            if (rnd.nextBoolean()) {
                yDelta *= -1;
            }
        }

        public void move(int x, int y) {
            location.setLocation(x, y);
        }

        public void evaluatePosition(Dimension bounds) {
            int x = location.x + xDelta;
            int y = location.y + yDelta;

            if (x < 0) {
                x = 0;
                xDelta *= -1;
            } else if (x + shape.getBounds().width > bounds.width) {
                x = bounds.width - shape.getBounds().width;
                xDelta *= -1;
            }
            if (y < 0) {
                y = 0;
                yDelta *= -1;
            } else if (y + shape.getBounds().height > bounds.height) {
                y = bounds.height - shape.getBounds().height;
                yDelta *= -1;
            }

            location.setLocation(x, y);
        }

        public Shape getTranslatedShape() {
            PathIterator pi = shape.getPathIterator(AffineTransform.getTranslateInstance(location.x, location.y));
            GeneralPath path = new GeneralPath();
            path.append(pi, true);
            return path;
        }

    }
}

您还可以查看

了解更多例子......