在JPanel中绘制钟摆随时间的旋转

时间:2014-01-12 06:55:50

标签: java jpanel bufferedimage paintcomponent graphics2d

我试图在JPanel中描述摆臂随时间的演变。 钟摆具有固定节点,而另一个节点基于固定的一个和从文件中取出的一些角度来计算。每隔1秒我就会看到用新坐标重新绘制钟摆。 为了描述我的问题,我已经删除了文件和角度计算,请考虑将移动点保存到PointsList中。

我试图通过从RotateLine对象的构造函数中调用drawRotatingLine()方法来实现逐渐旋转。 在drawRotatingLine()方法中,我有一个for循环:

  • 根据PointsList of Points
  • 的值设置移动点的坐标
  • 引入1秒的睡眠
  • 并调用repaint()方法

麻烦的是,我只让我的程序绘制初始位置,然后是最后一个位置,中间的位置没有绘制。

从这里到那里将代码放在一起是非常不完整的。请原谅我滥用BufferedImage,Graphics2D以及在paintComponent(...)方法中对这些对象的调用对我来说并不完全清楚,我只需要完成程序,在我的经验的这个阶段,我发现JPanels上有相当复杂的绘图。

以下是整个代码:

public class RotateLine extends JPanel {

private static final int PREF_W = 600;
private static final int PREF_H = 600;
private static final int X1 = 100;
private static final int Y1 = 100;
private BufferedImage image;
private Graphics2D bufferedGraphics;
private static ArrayList<Point> pointsList;
private static Point p;
private int counter = 0;

public RotateLine () {
    pointsList = new ArrayList<Point>();
    p = new Point(X1, Y1);
    int X2 = 400;
    int Y2 = Y1;
    for (int count = 0; count < 4; count++) {
        pointsList.add(new Point(X2, Y2));
        X2 = X2 - 100;
        Y2 = Y2 + 100;
    }
    image = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_RGB);
    bufferedGraphics = image.createGraphics();
    drawRotatingLine();
}

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

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    bufferedGraphics.clearRect(0, 0, PREF_W, PREF_H);
    bufferedGraphics.setColor(Color.WHITE);
    bufferedGraphics.fillRect(0, 0, PREF_W, PREF_H);
    bufferedGraphics.setColor(Color.BLACK);
    bufferedGraphics.drawLine(X1, Y1, p.x, p.y);
    g.drawImage(image, 0, 0, this);
    Toolkit.getDefaultToolkit().sync();

}

public static void main(String[] args) {
    JFrame frame = new JFrame("clock");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(new RotateLine());
    frame.pack();
    frame.setVisible(true);
}

public void drawRotatingLine() {
    for (int i = 0; i < pointsList.size(); i++) {
        p.x = pointsList.get(i).x;
        p.y = pointsList.get(i).y;
        try {
            Thread.sleep(1000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Pendul.class.getName()).log(Level.SEVERE, null, ex);
        }
        repaint();
    }        
}

}

2 个答案:

答案 0 :(得分:5)

您的问题很常见:​​您在Swing事件线程上调用Thread.sleep(...),这将使您的整个应用程序进入休眠状态。而是读取并使用Swing Timer。在您使用Google Swing Timer教程之后,请在此网站上搜索Java Swing Timer Animation,了解如何将其用于动画的正确示例。

所以,

  • 你的计时器的延迟是你希望动画有的任何时间片延迟,尽管我建议它不是&lt; 12毫秒。
  • 在Timer的ActionListener的actionPerformed中,根据PointsList的值和索引
  • 设置移动点的坐标
  • 增加索引(非常重要)
  • 将索引修改为最大值
  • call repaint

答案 1 :(得分:0)

基于 Hovercraft Full of Eels 的回答,这是我使用Java Swing Timer Animation改变初始代码的方式:

public class RotateLine extends JPanel **implements ActionListener**{

private static final int PREF_W = 800;
private static final int PREF_H = 800;
private static final int X1 = 100;
private static final int Y1 = 100;
private static ArrayList<Point> pointsList;
private static Point p;
private int counter = 0;
private int index = 0;
**Timer time = new Timer(10, (ActionListener) this);**

public RotateLine () {
    pointsList = new ArrayList<Point>();
    p = new Point(X1, Y1);
    int X2 = 400;
    int Y2 = Y1;
    for (int count = 0; count < 300; count++) {
        pointsList.add(new Point(X2, Y2));
        X2 = X2 - 1;
        Y2 = Y2 + 2;
    }
    **time.start();**
}

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

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D)g;
    drawRotatingLine(g2d);
}

public static void main(String[] args) {
    JFrame frame = new JFrame("clock");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(new RotateLine());
    frame.pack();
    frame.setVisible(true);
}

public void drawRotatingLine(Graphics2D g) {
    g.drawLine(p.x, p.y, pointsList.get(index).x, pointsList.get(index).y);        
}

**public void actionPerformed(ActionEvent arg0) {
  if (index < pointsList.size() - 1){
  time.setDelay(20);
  repaint();
  index++;
  }
}**