2013-04-08 75 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。