2016-11-13 140 views
-1

该代码旨在绘制一个矩形,该矩形一次围绕画布中心移动一圈。我公司目前拥有的代码是如何绘制围绕画布中心的圆圈移动矩形?

import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.geom.Rectangle2D; 
import javax.swing.Timer; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 

public class Q3_Circular extends JComponent { 

protected int degree = 0; 
protected double xStart; 
protected double yStart; 
protected Timer timer; 


public Q3_Circular() { 
    timer = new Timer(1000, new TimerCallback()); //creates new times that refreshes every 100 ms, and called the TimerCallback class 
    timer.start(); 
} 

protected class TimerCallback implements ActionListener { 

    public void actionPerformed(ActionEvent e) { 

     if (degree < (2 * Math.PI)){ 
      xStart = getWidth()/2 * Math.cos(degree+1); 
      yStart = getHeight()/2 * Math.sin(degree+1); 
      degree+= 1; 
      repaint(); 
     } 
     else { 
      degree += 0; 
      repaint(); 
     } 

    } 
} 


public static void main(String[] args) { 
    JFrame frame = new JFrame("AnimatedSquare"); 
    Q3_Circular canvas = new Q3_Circular(); 
    frame.add(canvas); 
    frame.setSize(300, 300); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
    frame.setVisible(true); 
} 

public void paintComponent(Graphics g){ 
    xStart = (double)(getWidth())/2.0 * Math.cos(degree); 
    yStart = (double)(getHeight())/2.0 * Math.sin(degree); 

    Graphics2D g2 = (Graphics2D) g; 
    g2.draw(new Rectangle2D.Double(xStart,yStart, 25,25)); 
    repaint(); 
} 
} 

此代码出现非常迅速地绘制矩形围绕点(0,0)。我不确定代码出错的地方。

+1

您需要知道'Math#cos'和'Math#sin'中的'degree'参数假设为* Radian *而非Degrees。此外,您应该知道,对于某些输入,“sin”和“cos”函数的输出可以是** Negative **。所以你的'xStart'和'yStart'被计算为负值,然后在你的帧之外绘制。另外,当您在'paintComponent'方法中计算'xStart'和'yStart'时,您将忽略'actionPerformed'方法中的计算。询问任何问题,如果这些提示没有帮助。 – STaefi

+0

顺便说一句,虽然它没有回答你的问题,但可能它可以简化你的代码。在Graphics2D中,您可以使用仿射变换进行旋转。他们基本上会让你摆脱三角函数。请阅读此处:http://docs.oracle.com/javase/tutorial/2d/advanced/transforming.html –

+0

谢谢,这非常有帮助。我仍然遇到的唯一问题是它围绕点0,0围绕点(getWidth()/ 2,getHeight()/ 2)旋转。 –

回答

1

你的代码很混乱。这是我创建的GUI。

Animated Square

当创建一个Swing GUI,使用该模型/视图/控制器模式。创建GUI模型和GUI视图,以及一个或多个控制器来修改模型并重新绘制视图。

以下是我对代码所做的更改。

  1. 我创建了一个DrawingRectangle类来保存关于绘制矩形的信息。这个类是一个普通的旧Java对象,带有getter和setter。这个类是GUI模型。

  2. 除了调用SwingUtilities invokeLater方法外,我将所有东西都移出了主方法。 invokeLater方法将创建和使用Swing组件的操作放在Event Dispatch thread上。 Oracle和我坚持所有的Swing应用程序都从Event Dispatch线程开始。

  3. 我在Q3_Circular类的构造函数中创建绘制矩形。通常,您将创建GUI模型,然后创建GUI视图。

  4. 我重新安排了run方法中的JFrame代码,使其处于正确的顺序。我删除了setSize方法并用pack方法替换它。我们不在乎JFrame有多大。我们关心绘图板有多大。

  5. 我从JPanel创建了一个绘图面板。在这里,我们设置了绘图面板的首选大小。我们扩展一个JPanel,所以我们可以覆盖paintComponent方法。

  6. paintComponent方法除了绘制绘制矩形外什么也不做。 paintComponent方法中没有任何计算或绘画。我添加了对super paintComponent方法的调用,以在绘制绘制矩形之前维护Swing绘画链并清除绘图面板。我使用x和y坐标作为矩形的中心而不是左上角绘制矩形。这是我在绘图代码中做的一个转换。

  7. 我从Runnable创建了一个绘制动画。如果你愿意,你可以使用Swing Timer。我发现创建我自己的动画代码更容易。这是GUI控制器。这里是我们进行计算的地方,更新模型并重绘绘图面板。在重绘方法中,我使用SwingUtilities invokeLater方法在Event Dispatch线程上绘画。我这样做是因为动画线程是一个单独的线程。

下面的代码。我把所有的类放在一起,这样我可以更容易地粘贴代码。你应该将这些类分成不同的文件。

package com.ggl.testing; 

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.geom.Rectangle2D; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class Q3_Circular implements Runnable { 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Q3_Circular()); 
    } 

    private static final int DRAWING_WIDTH = 300; 
    private static final int DRAWING_HEIGHT = DRAWING_WIDTH; 

    private DrawingRectangle drawingRectangle; 

    public Q3_Circular() { 
     int center = DRAWING_WIDTH/2; 
     Rectangle2D rectangle = new Rectangle2D.Double(center, center, 32D, 32D); 
     drawingRectangle = new DrawingRectangle(Color.RED, rectangle); 
    } 

    @Override 
    public void run() { 
     JFrame frame = new JFrame("Animated Square"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     DrawingPanel drawingPanel = new DrawingPanel(DRAWING_WIDTH, 
       DRAWING_HEIGHT, drawingRectangle); 
     frame.add(drawingPanel); 

     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 

     new Thread(new DrawingAnimation(drawingPanel, drawingRectangle)) 
       .start(); 
    } 

    public class DrawingPanel extends JPanel { 

     private static final long serialVersionUID = 8226587438110549806L; 

     private DrawingRectangle drawingRectangle; 

     public DrawingPanel(int width, int height, 
       DrawingRectangle drawingRectangle) { 
      this.setPreferredSize(new Dimension(width, height)); 
      this.drawingRectangle = drawingRectangle; 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 

      g.setColor(drawingRectangle.getColor()); 

      Rectangle2D rectangle = drawingRectangle.getRectangle(); 
      int x = (int) Math.round(rectangle.getX()); 
      int y = (int) Math.round(rectangle.getY()); 
      int width = (int) Math.round(rectangle.getWidth()); 
      int height = (int) Math.round(rectangle.getHeight()); 
      g.fillRect(x - width/2, y - height/2, width, height); 
     } 

    } 

    public class DrawingAnimation implements Runnable { 

     private DrawingPanel drawingPanel; 

     private DrawingRectangle drawingRectangle; 

     public DrawingAnimation(DrawingPanel drawingPanel, 
       DrawingRectangle drawingRectangle) { 
      this.drawingPanel = drawingPanel; 
      this.drawingRectangle = drawingRectangle; 
     } 

     @Override 
     public void run() { 
      int xCenter = drawingPanel.getWidth()/2; 
      int yCenter = drawingPanel.getHeight()/2; 
      double radius = drawingPanel.getWidth()/3; 

      for (int degree = 0; degree < 360; degree++) { 
       double radians = Math.toRadians((double) degree); 
       double x = radius * Math.cos(radians) + xCenter; 
       double y = radius * Math.sin(radians) + yCenter; 
       drawingRectangle.setRectangleOrigin(x, y); 
       repaint(); 
       sleep(100L); 
      } 
     } 

     private void sleep(long interval) { 
      try { 
       Thread.sleep(interval); 
      } catch (InterruptedException e) { 

      } 
     } 

     private void repaint() { 
      SwingUtilities.invokeLater(new Runnable() { 
       @Override 
       public void run() { 
        drawingPanel.repaint(); 
       } 
      }); 
     } 
    } 

    public class DrawingRectangle { 

     private final Color color; 

     private Rectangle2D rectangle; 

     public DrawingRectangle(Color color, Rectangle2D rectangle) { 
      this.color = color; 
      this.rectangle = rectangle; 
     } 

     public void setRectangleOrigin(double x, double y) { 
      rectangle 
        .setRect(x, y, rectangle.getWidth(), rectangle.getHeight()); 
     } 

     public Color getColor() { 
      return color; 
     } 

     public Rectangle2D getRectangle() { 
      return rectangle; 
     } 

    } 

}