简体   繁体   English

重绘方法会在短暂的延迟后停止工作

[英]The repaint method stops working for short delays

I'm trying to create a simple panel where a 2-dimensional ball is bouncing up and down. 我正在尝试创建一个简单的面板,其中二维球在上下反弹。 I can't get it to work because for some reason I can't call the repaint method more than once a second. 我无法使其正常工作,因为出于某种原因,我不能多次调用repaint方法。 The design is basically that there is an object that can be given "an impulse" with the method move() . 设计基本上是使用move()方法可以给对象一个“冲动”。 Everytime the evaluatePosition method is called, the current position will be calculated through the time that has passed, the velocity and the acceleration. 每次的evaluatePosition方法被调用时,所述当前位置将通过已经通过,速度和加速度的时间来计算。 The code for the panel is: 该面板的代码是:

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());
}

This code works for DELAY=1000 but not for DELAY=100 or DELAY=10 and so on. 此代码适用于DELAY = 1000,但不适用于DELAY = 100或DELAY = 10,依此类推。 I read some example code here on SO but they all seem to me like what I already did. 我在这里阅读了一些示例代码,但在我看来它们都像我已经做过的那样。 So why is my code not working? 那么为什么我的代码不起作用?

EDIT (2016-01-30): Since it really seems to be a performance issue, here's the code for the MovableObject (I just thought it would be irrelevant and you will probably see why): 编辑(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;
}

My move method does not change position but velocity. 我的移动方法不改变位置,而是改变速度。 Please notice that I just changed the shape Object from Shape to Ellipse2D for testing if my code has a performance issue because of the additional code. 请注意 ,我只是将Shape对象从Shape更改为Ellipse2D,以测试我的代码是否由于附加代码而出现性能问题。 So if you think this is more complex than it needs to be: I actually want to add some complexity so that the MovableObject can have the shape of any subclass of shape. 因此,如果您认为这比需要的更为复杂:我实际上是想增加一些复杂度,以便MovableObject可以具有shape的任何子类的形状。 I've seen a lot of code that seemed more complex to me and rendered fast. 我看过很多代码,这些代码对我来说似乎更复杂,而且渲染速度很快。 So I'd like to know what's wrong with this (besides the fact that it's a bit too complex for just rendering an ellipse). 因此,我想知道这是怎么回事(除了对于渲染椭圆来说太复杂了这一事实)。

Okay, so this is a simple example, based on the out-of-context code snippet you left which doesn't seem to have any problems. 好的,这是一个简单的示例,基于您留下的上下文外代码片段,这似乎没有任何问题。 It has variable speed controlled by a simple slider... 它具有通过简单的滑块控制的变速...

弹跳

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;
        }

    }
}

You could also have a look at 您也可以看看

for some more examples... 有关更多示例...

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

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