2013-04-08 80 views
2

我一直在使用Path2D.Double约一天左右, 我询问了有关设置控制点以允许路径通过指定点的帮助。我将一些代码作为一个快速测试平台混合在一起,随机生成点,然后根据上述文章中提到的信息将路径曲线转换为这些点。Path2D绘制错误?

这里是可运行的代码,很抱歉它是铁板一块,我想这是过帐,所以你可以跟着:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics2D; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.geom.Path2D; 
import java.awt.geom.Point2D; 
import java.util.ArrayList; 
import java.util.Random; 
import javax.swing.JFrame; 

public class Curver { 
    public static ArrayList<Point2D> points = new ArrayList<Point2D>(); 
    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 

     final JFrame window = new JFrame(); 
     window.setPreferredSize(new Dimension(500,500)); 
     window.setLocationRelativeTo(null); 

     window.addMouseListener(new MouseListener() { 

      @Override 
      public void mouseReleased(MouseEvent e) { 
       // TODO Auto-generated method stub 

      } 

      @Override 
      public void mousePressed(MouseEvent e) { 
       // TODO Auto-generated method stub 

      } 

      @Override 
      public void mouseExited(MouseEvent e) { 
       // TODO Auto-generated method stub 

      } 

      @Override 
      public void mouseEntered(MouseEvent e) { 
       // TODO Auto-generated method stub 

      } 

      @Override 
      public void mouseClicked(MouseEvent e) { 
       new Thread(new Runnable(){ 
        @Override 
        public void run() { 

         Random random = new Random(); 

         while(true){ 

          points.add(new Point2D.Double(random.nextInt(window.getWidth()-1)+1,random.nextInt(window.getHeight()-1)+1)); 
          System.out.println(points.size()); 

          try { 
           Thread.sleep(500); 
          } catch (InterruptedException e) { 
           // TODO Auto-generated catch block 
           e.printStackTrace(); 
          } 

         } 

        } 

       }).start(); 
      } 
     }); 


     window.pack(); 
     window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     window.setVisible(true); 

     int div = 7; 
     int d = 4; 

     Path2D.Double path = new Path2D.Double(); 
     Point2D currentPoint; 
     double startX, startY; 
     double interiorX_In, interiorY_In; 
     double interiorX_Out, interiorY_Out; 
     double endX, endY; 

     Graphics2D g; 


     while(true){ 

      g = (Graphics2D) window.getGraphics(); 
      g.setColor(Color.blue); 

      for(int i = 0; i < points.size(); i++){ 

       currentPoint = points.get(i); 
       g.fillRect((int)currentPoint.getX(), (int)currentPoint.getY(), d, d); 

       if (i == 0){ 
        // Don't attempt any line drawing as we don't have enough points. 
        path.moveTo(currentPoint.getX(), currentPoint.getY()); 
       } else if (i == 1 && points.size() > 2){ 
        // draw first curve with knowledge of third point (third point is not end point) 
        startX = points.get(i-1).getX() + (currentPoint.getX() - points.get(i-1).getX())/div; // from start 
        startY = points.get(i-1).getY() + (currentPoint.getY() - points.get(i-1).getY())/div; 

        interiorX_In = currentPoint.getX() - (points.get(i+1).getX() - points.get(i-1).getX())/div; // to interior 
        interiorY_In = currentPoint.getY() - (points.get(i+1).getY() - points.get(i-1).getY())/div; 

        path.curveTo(startX, startY, interiorX_In, interiorY_In, currentPoint.getX(), currentPoint.getY()); 

       } else if (i == 1){ // Only 2 points in list so use a straight line until more points are available. 
        g.drawLine((int) points.get(i-1).getX(), (int) points.get(i-1).getY(), (int)currentPoint.getX(), (int)currentPoint.getY()); 
       } else if (i >= 1 && i < points.size()-1){ // interior to interior edge. 

        interiorX_Out = points.get(i-1).getX() + (currentPoint.getX() - points.get(i-2).getX())/div; // from interior 
        interiorY_Out = points.get(i-1).getY() + (currentPoint.getY() - points.get(i-2).getY())/div; 

        interiorX_In = currentPoint.getX() - (points.get(i+1).getX() - points.get(i-1).getX())/div; // to interior 
        interiorY_In = currentPoint.getY() - (points.get(i+1).getY() - points.get(i-1).getY())/div; 

        path.curveTo(interiorX_Out, interiorY_Out, interiorX_In, interiorY_In, currentPoint.getX(), currentPoint.getY()); 

       } else { // from interior point to end point. 

        interiorX_Out = points.get(i-1).getX() + (currentPoint.getX() - points.get(i-2).getX())/div; // from interior 
        interiorY_Out = points.get(i-1).getY() + (currentPoint.getY() - points.get(i-2).getY())/div; 

        endX = currentPoint.getX() - (currentPoint.getX() - points.get(i-1).getX())/div; // to end 
        endY = currentPoint.getY() - (currentPoint.getY() - points.get(i-1).getY())/div; 

        path.curveTo(interiorX_Out, interiorY_Out, endX, endY, currentPoint.getX(), currentPoint.getY()); 

       } 

      } // end for 

      g.clearRect(0, 0, window.getWidth(), window.getHeight()); 
      g.draw(path); 
      path.reset(); 


      try { 
       Thread.sleep(100); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 
  • 只需点击JFrame中开始绘制随机点 - 控制台会报告绘制的点数。

我遇到的问题是,一旦我得到向上或60-65随机点的路径闪烁,似乎在屏幕上缩小,一般表现出奇怪的行为? 正如我所说的代码可能不完美,所以任何人都可以给我一些关于如何使它减少错误的指针。

我假设奇怪的行为来自于构建JFrame重绘的更长和更长的路径?或许我可以将路径描绘为一条连续的路线,因为我认为路径被解释为一系列的路段?或者可能使路径累积,而不是重构整个运行循环的每个迭代?

期待提出的任何建议 - 但请尽量解释,因为我是比较新的绘画和路径等提前

感谢。


感谢@camickr的发帖。 这里是重新编写代码,完美的作品,3,500+随机点,而不是一个单一的故障:

> import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.geom.Path2D; 
import java.awt.geom.Point2D; 
import java.util.ArrayList; 
import java.util.Random; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.Timer; 

public class Curver extends JFrame implements ActionListener, MouseListener{ 

    public Timer animationTicker = new Timer(50, this); 
    public ArrayList<Point2D> points = new ArrayList<Point2D>(); 
    private Canvas canvas; 

    public Curver(){ 
     this.setPreferredSize(new Dimension(500,500)); 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     this.setLocationRelativeTo(null); 
     this.setLayout(new BorderLayout()); 
     canvas = new Canvas(points); 
     this.add(canvas, BorderLayout.CENTER); 
     this.addMouseListener(this); 
     this.pack(); 
     this.setVisible(true); 
    } 

    class Canvas extends JPanel{ 

     int div = 7; 
     int d = 4; 

     Path2D.Double path = new Path2D.Double(); 
     Point2D currentPoint; 
     double startX, startY; 
     double interiorX_In, interiorY_In; 
     double interiorX_Out, interiorY_Out; 
     double endX, endY; 
     Graphics2D g2; 
     ArrayList<Point2D> points; 

     public Canvas(ArrayList<Point2D> points){ 
      this.setMinimumSize(new Dimension(100,100)); 
      this.points = points; 
     } 

     @Override 
     public void paintComponent(Graphics g) { 

      g2 = (Graphics2D) g; 
      g.setColor(Color.blue); 

      synchronized(points){ 
      for(int i = 0; i < points.size(); i++){ 

       currentPoint = points.get(i); 
       g2.fillRect((int)currentPoint.getX(), (int)currentPoint.getY(), d, d); 

       if (i == 0){ 
        // Don't attempt any line drawing as we don't have enough points. 
        path.moveTo(currentPoint.getX(), currentPoint.getY()); 
       } else if (i == 1 && points.size() > 2){ 
        // draw first curve with knowledge of third point (third point is not end point) 
        startX = points.get(i-1).getX() + (currentPoint.getX() - points.get(i-1).getX())/div; // from start 
        startY = points.get(i-1).getY() + (currentPoint.getY() - points.get(i-1).getY())/div; 

        interiorX_In = currentPoint.getX() - (points.get(i+1).getX() - points.get(i-1).getX())/div; // to interior 
        interiorY_In = currentPoint.getY() - (points.get(i+1).getY() - points.get(i-1).getY())/div; 

        path.curveTo(startX, startY, interiorX_In, interiorY_In, currentPoint.getX(), currentPoint.getY()); 

       } else if (i == 1){ // Only 2 points in list so use a straight line until more points are available. 
        g2.drawLine((int) points.get(i-1).getX(), (int) points.get(i-1).getY(), (int)currentPoint.getX(), (int)currentPoint.getY()); 
       } else if (i >= 1 && i < points.size()-1){ // interior to interior edge. 

        interiorX_Out = points.get(i-1).getX() + (currentPoint.getX() - points.get(i-2).getX())/div; // from interior 
        interiorY_Out = points.get(i-1).getY() + (currentPoint.getY() - points.get(i-2).getY())/div; 

        interiorX_In = currentPoint.getX() - (points.get(i+1).getX() - points.get(i-1).getX())/div; // to interior 
        interiorY_In = currentPoint.getY() - (points.get(i+1).getY() - points.get(i-1).getY())/div; 

        path.curveTo(interiorX_Out, interiorY_Out, interiorX_In, interiorY_In, currentPoint.getX(), currentPoint.getY()); 

       } else { // from interior point to end point. 

        interiorX_Out = points.get(i-1).getX() + (currentPoint.getX() - points.get(i-2).getX())/div; // from interior 
        interiorY_Out = points.get(i-1).getY() + (currentPoint.getY() - points.get(i-2).getY())/div; 

        endX = currentPoint.getX() - (currentPoint.getX() - points.get(i-1).getX())/div; // to end 
        endY = currentPoint.getY() - (currentPoint.getY() - points.get(i-1).getY())/div; 

        path.curveTo(interiorX_Out, interiorY_Out, endX, endY, currentPoint.getX(), currentPoint.getY()); 

       } 

      } // end for 

      g.clearRect(0, 0, this.getWidth(), this.getHeight()); 
      g2.draw(path); 
      path.reset(); 
      } 
     } 
    } // end of inner class 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     this.canvas.repaint(); 
    } 

    @Override 
    public void mouseClicked(MouseEvent e) { 
     new Thread(new Runnable(){ 
      @Override 
      public void run() { 
       System.out.println("Thread running"); 
       Random random = new Random(); 

       while(true){ 
        synchronized(points){ 
         points.add(new Point2D.Double(random.nextInt(getWidth()-1)+1,random.nextInt(getHeight()-1)+1)); 
         System.out.println(points.size()); 
        } 
        try { 
         Thread.sleep(60); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 

       } 

      } 

     }).start(); 
    } 

    @Override 
    public void mousePressed(MouseEvent e) {} 

    @Override 
    public void mouseReleased(MouseEvent e) {} 

    @Override 
    public void mouseEntered(MouseEvent e) {} 

    @Override 
    public void mouseExited(MouseEvent e) {} 


    public static void main(String[] args) { 
     Curver curver = new Curver(); 
     curver.animationTicker.start(); 
    } 
} 
+0

它可能不是主要问题,但它可能无助于从两个线程访问点列表而没有任何同步。尝试在绘制和添加点之前用'synchronized(points){...}'锁定列表。 – Boann 2013-04-08 16:31:16

+0

@Boann我明白你在说什么,但是如果没有鼠标点击处理程序中的线程,这个问题是可重复的 - 我只把它放在那里,因为每次调试我都感到厌倦了50 - 70次鼠标点击。你会看到如果你将随机点逻辑移出线程,问题依然存在。 – 2013-04-08 16:35:37

回答

4
g = (Graphics2D) window.getGraphics(); 

我没有在你的代码看起来太紧密,但论坛的建议是不使用getGraphics()方法来绘画。

自定义绘画是通过覆盖JPanel(或JComponent)的paintComponent()方法完成的。然后将面板添加到框架。阅读Swing教程以获取更多关于自定义绘画的信息。

另外,不要使用“while(true)”逻辑。 Swing将根据需要重新绘制。如果您需要某种动画,请使用Swing Timer。