2010-12-04 91 views
0

我寫了一個程序,我認爲應該完美地工作。由於某種原因,它沒有。我將提供代碼並希望有人能夠弄清楚什麼是錯的。我一直坐着幾個小時,但我無法進一步。奇怪的隨機錯誤,java繪圖

import java.awt.*; 
import javax.swing.*; 

public class CrystalModel 
{ 
    private int radius; 
    private int index; 
    private boolean[][] crystal; 
    private Point concludingPoint; 
    private int escapeRadius; 

    /** 
    * Constructor. Initiates an electron bath of size 30x30. 
    */ 
    public CrystalModel() 
    { 
     radius = 30; 
     index = 30*2-1; 
     start(); 
    } 

    /** 
    * Constructor. Initiates an electron bath of size r. 
    * @param r bath radius 
    */ 
    public CrystalModel(int r) 
    { 
     radius = r; 
     index = r*2-1; 
     start(); 
    } 

    /** 
    * Initiates the experiment 
    */ 
    private void start() 
    { 
     crystal = new boolean[radius*2][radius*2]; 
     crystal[radius][radius] = true; //The width is always even (2*r), this is as close to the center as one gets 
     escapeRadius = (int)(1.1*radius); 
    } 

    /** 
    * Determines if a given xy-coordinate is within radius 
    * @param x x-coordinate 
    * @param y y-coordinate 
    * @return whether the active ion is out of range 
    */ 
    private boolean outsideCircle(int r, int x, int y) 
    { 
     return (Math.pow(x,2)+Math.pow(y,2) >= Math.pow(r, 2)); 
    } 

    /** 
    * Determines if the currently active ion has a neighbouring crystallized ion 
    * @param whether the is a neighbour 
    */ 
    private boolean anyNeighbours(int x, int y) 
    { 
      x = xBathToModel(x); 
      y = yBathToModel(y); 

      boolean left = (x-1 >= 0) && (x-1 <= index) && (y >= 0) && (y <= index) ? crystal[x-1][y] : false; 
      boolean right = (x+1 >= 0) && (x+1 <= index) && (y >= 0) && (y <= index) ? crystal[x+1][y] : false; 
      boolean up  = (y-1 >= 0) && (y-1 <= index) && (x >= 0) && (x <= index) ? crystal[x][y-1] : false; 
      boolean down = (y+1 >= 0) && (y+1 <= index) && (x >= 0) && (x <= index) ? crystal[x][y+1] : false; 

      return (left || right || up || down); 
    } 

    /** 
    * Determines an xy-coordinate at radius distance from the center 
    * @param radius radius of escape for ions 
    * @return Point object encapsulating x, y 
    */ 
    private Point dropNewIon() 
    { 
     double angle = (int)(Math.random()*2*Math.PI); 
     return new Point((int)(Math.cos(angle)*(index/2)), (int)(Math.sin(angle)*(index/2))); 
    } 

    /** 
    * Transform x-coordinate upon the moving of origo from center to top-left 
    * @ x x-coordinate 
    */ 
    public int xBathToModel(int x) 
    { 
     return radius+x; 
    } 

    /** 
    * Transform y-coordinate upon the moving of origo from center to top-left 
    * @param y y-coordinate 
    */ 
    public int yBathToModel(int y) 
    { 
     return radius+y; 
    } 

    /** 
    * Increments the number of ions in the crystal by one 
    * @return boolean indicating whether the experiment is done or not 
    */ 
    private Point crystallizeOneIon() 
    { 
     Point point = dropNewIon(); 
     for(; ;) 
     { 
      switch((int)(Math.random()*4+1)) 
      { 
       case 1: point.x+=1; 
        break; 
       case 2: point.x-=1; 
        break; 
       case 3: point.y+=1; 
        break; 
       case 4: point.y-=1; 
        break; 
      } 

      if(outsideCircle(escapeRadius, point.x, point.y)) point = dropNewIon(); 

      if(anyNeighbours(point.x, point.y)) break; 
     } 

     crystal[xBathToModel(point.x)][yBathToModel(point.y)] = true; 
     return point; 
    } 

    /** 
    * Let the algorithm (CrystalExperiment) simulate a number of steps 
    * @param steps how many steps 
    * @return boolean indiciating whether the experiment is concluded 
    */ 
    public boolean runExperiment(int steps) 
    { 
     for(int i=0; i<steps; i++) 
     { 
      concludingPoint = crystallizeOneIon(); 

      if(outsideCircle((int)index/2, concludingPoint.x, concludingPoint.y)) 
      { 
       concludingPoint.x = xBathToModel(concludingPoint.x); 
       concludingPoint.y = yBathToModel(concludingPoint.y); 
       return true; 
      } 
      else 
      { 
       concludingPoint.x = xBathToModel(concludingPoint.x); 
       concludingPoint.y = yBathToModel(concludingPoint.y); 
      } 
     } 

     return false; 
    } 

    /** 
    * Return a textual representation of the crystal 
    * @return String representing the crystal 
    */ 
    public String toString() 
    { 
     String output = ""; 
     for(int y=-1; y<=index+1; y++) 
     { 
      for(int x=-1; x<=index+1; x++) 
      { 
       if(y == -1) output+="--"; 
       else if(y == index+1) output+="--"; 
       else 
       { 
        if(x == -1) output+="|"; 
        else if(x == index+1) output+="|"; 
        else 
        { 
         if(concludingPoint.equals(new Point(x,y))) output+="# "; 
         else if(crystal[x][y] == true) output+="* "; 
         else output+=" "; 
        } 
       } 
      } 
      output+="\n"; 
     } 

     return output; 
    } 

    public int getIndexSize() 
    { 
     return index; 
    } 

    public boolean getMatrixValue(int x, int y) 
    { 
     return crystal[x][y]; 
    } 

    private void drawCrystal() 
    { 
     JFrame frame = new JFrame(""); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
     frame.setBounds(0, 0, 200, 200); 

     CrystalView drawing = new CrystalView(this); 
     frame.add(drawing); 
    } 

    public static void main(String[] args) 
    { 
     (new CrystalModel(200)).drawCrystal(); 
    } 

} 

這是我的看法,這是行不通的(雖然toString方法的工作原理,這是類似):

import javax.swing.*; 
import java.awt.*; 

public class CrystalView extends JPanel 
{ 
    CrystalModel model; 
    public CrystalView(CrystalModel m) 
    { 
     model = m; 
    } 

    public void paintComponent(Graphics g) 
    { 
     while(!model.runExperiment(1)) 
     { 
      for(int y=0; y<model.getIndexSize(); y++) 
      { 
       for(int x=0; x<model.getIndexSize(); x++) 
       { 
        if(model.getMatrixValue(x,y)) 
        g.drawOval(x, y, 1, 1); 
       } 
      } 
      this.repaint(); 
     } 
    } 
} 

的錯誤是在圖形中。它(1)在終端中產生錯誤,並且(2)不繪製完整尺寸。請運行程序,你會明白我的意思。

+1

* 「請運行該程序,你會明白我的意思。」 *。不,我不會。如果你想得到一些幫助,你需要付出一些努力來告訴我們問題是什麼。 – 2010-12-04 23:36:37

+0

問題很簡單。例如,如果您查看for循環,則循環遍歷1-200,並在此區域內填充像素(200x200)。但是如果你畫出來,這個數字就會變得很小。如果它吸引了,那就是。只有200px的大小會完全凍結,所以我想我正在做一些減緩它的事情。 – 2010-12-04 23:39:28

+0

另外,只關注繪圖部分,因爲我已經驗證了模型的工作原理。 toString返回圖形應該看起來像的正確圖像。 – 2010-12-04 23:54:51

回答

1
public void paintComponent(Graphics g) 
{ 
    while(!model.runExperiment(1)) 
    { 
     for(int y=0; y<model.getIndexSize(); y++) 
     { 
      for(int x=0; x<model.getIndexSize(); x++) 
      { 
       if(model.getMatrixValue(x,y)) 
       g.drawOval(x, y, 1, 1); 
      } 
     } 
     this.repaint(); 
    } 
} 

我不知道代碼應該做什麼,但你永遠不應該有一個像這樣調用repaint()的循環。這是導致無限循環的一種方式。

如果您正在嘗試製作動畫,則需要使用線程或擺動計時器來執行動畫。

1

我試圖修復你的代碼(見下文)。問題所在地標有TODO。不知道它打算如何工作,但現在它吸取了一些觀點。

正如在前面的回答中提到的,你不能得到像這樣的動畫。 paintComponent()方法僅被調用一次以繪製組件。例如,當表單被調整大小時會發生這種情況。所以你只能得到靜態圖像。

CrystalModel.java

import java.awt.Point; 
import javax.swing.JFrame; 

public class CrystalModel 
{ 
    private int radius; 
    private int index; 
    private boolean[][] crystal; 
    private Point concludingPoint; 
    private int escapeRadius; 

    /** 
    * Constructor. Initiates an electron bath of size 30x30. 
    */ 
    public CrystalModel() 
    { 
     radius = 30; 
     index = 30*2-1; 
     start(); 
    } 

    /** 
    * Constructor. Initiates an electron bath of size r. 
    * @param r bath radius 
    */ 
    public CrystalModel(int r) 
    { 
     radius = r; 
     index = r*2-1; 
     start(); 
    } 

    /** 
    * Initiates the experiment 
    */ 
    private void start() 
    { 
     crystal = new boolean[radius*2][radius*2]; 
     crystal[radius][radius] = true; //The width is always even (2*r), this is as close to the center as one gets 
     escapeRadius = (int)(1.1*radius); 
    } 

    /** 
    * Determines if a given xy-coordinate is within radius 
    * @param x x-coordinate 
    * @param y y-coordinate 
    * @return whether the active ion is out of range 
    */ 
    private boolean outsideCircle(int r, int x, int y) 
    { 
     return (Math.pow(x,2)+Math.pow(y,2) >= Math.pow(r, 2)); 
    } 

    /** 
    * Determines if the currently active ion has a neighbouring crystallized ion 
    * @param whether the is a neighbour 
    */ 
    private boolean anyNeighbours(int x, int y) 
    { 
      x = xBathToModel(x); 
      y = yBathToModel(y); 

      boolean left = (x-1 >= 0) && (x-1 <= index) && (y >= 0) && (y <= index) ? crystal[x-1][y] : false; 
      boolean right = (x+1 >= 0) && (x+1 <= index) && (y >= 0) && (y <= index) ? crystal[x+1][y] : false; 
      boolean up  = (y-1 >= 0) && (y-1 <= index) && (x >= 0) && (x <= index) ? crystal[x][y-1] : false; 
      boolean down = (y+1 >= 0) && (y+1 <= index) && (x >= 0) && (x <= index) ? crystal[x][y+1] : false; 

      return (left || right || up || down); 
    } 

    /** 
    * Determines an xy-coordinate at radius distance from the center 
    * @param radius radius of escape for ions 
    * @return Point object encapsulating x, y 
    */ 
    private Point dropNewIon() 
    { 
     double angle = (int)(Math.random()*2*Math.PI); 
     return new Point((int)(Math.cos(angle)*(index/2)), (int)(Math.sin(angle)*(index/2))); 
    } 

    /** 
    * Transform x-coordinate upon the moving of origo from center to top-left 
    * @ x x-coordinate 
    */ 
    public int xBathToModel(int x) 
    { 
     return radius+x; 
    } 

    /** 
    * Transform y-coordinate upon the moving of origo from center to top-left 
    * @param y y-coordinate 
    */ 
    public int yBathToModel(int y) 
    { 
     return radius+y; 
    } 

    /** 
    * Increments the number of ions in the crystal by one 
    * @return boolean indicating whether the experiment is done or not 
    */ 
    private Point crystallizeOneIon() 
    { 
     Point point = dropNewIon(); 
     for(; ;) 
     { 
      switch((int)(Math.random()*4+1)) 
      { 
       case 1: point.x+=1; 
        break; 
       case 2: point.x-=1; 
        break; 
       case 3: point.y+=1; 
        break; 
       case 4: point.y-=1; 
        break; 
      } 

      if(outsideCircle(escapeRadius, point.x, point.y)) point = dropNewIon(); 

      if(anyNeighbours(point.x, point.y)) break; 
      break; 
     } 

     try { 
      // TODO The logic is wrong here - calculated points sometimes are out of array. See console output 
      crystal[xBathToModel(point.x)][yBathToModel(point.y)] = true; 
     } catch (ArrayIndexOutOfBoundsException e) { 
      System.out.println("Oops, point (" + point.x + ", " + point.y + ") is out of array"); 
     } 
     return point; 
    } 

    /** 
    * Let the algorithm (CrystalExperiment) simulate a number of steps 
    * @param steps how many steps 
    * @return boolean indiciating whether the experiment is concluded 
    */ 
    public synchronized boolean runExperiment(int steps) 
    { 
     for(int i=0; i<steps; i++) 
     { 
      concludingPoint = crystallizeOneIon(); 

      if(outsideCircle((int)index/2, concludingPoint.x, concludingPoint.y)) 
      { 
       concludingPoint.x = xBathToModel(concludingPoint.x); 
       concludingPoint.y = yBathToModel(concludingPoint.y); 
       return true; 
      } 
      else 
      { 
       concludingPoint.x = xBathToModel(concludingPoint.x); 
       concludingPoint.y = yBathToModel(concludingPoint.y); 
      } 
     } 

     return false; 
    } 

    /** 
    * Return a textual representation of the crystal 
    * @return String representing the crystal 
    */ 
    public String toString() 
    { 
     String output = ""; 
     for(int y=-1; y<=index+1; y++) 
     { 
      for(int x=-1; x<=index+1; x++) 
      { 
       if(y == -1) output+="--"; 
       else if(y == index+1) output+="--"; 
       else 
       { 
        if(x == -1) output+="|"; 
        else if(x == index+1) output+="|"; 
        else 
        { 
         if(concludingPoint.equals(new Point(x,y))) output+="# "; 
         else if(crystal[x][y] == true) output+="* "; 
         else output+=" "; 
        } 
       } 
      } 
      output+="\n"; 
     } 

     return output; 
    } 

    public int getIndexSize() 
    { 
     return index; 
    } 

    public boolean getMatrixValue(int x, int y) 
    { 
     return crystal[x][y]; 
    } 

    private void drawCrystal() 
    { 
     JFrame frame = new JFrame(""); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
     frame.setBounds(0, 0, 600, 600); 

     CrystalView drawing = new CrystalView(this); 
     frame.add(drawing); 
     frame.validate(); 
    } 

    public static void main(String[] args) 
    { 
     (new CrystalModel(200)).drawCrystal(); 
    } 

} 

CrystalView.java

import java.awt.Graphics; 

import javax.swing.JPanel; 

public class CrystalView extends JPanel { 
    private static final long serialVersionUID = 1L; 

    CrystalModel model; 

    public CrystalView(CrystalModel m) { 
     model = m; 
    } 

    public void paintComponent(Graphics g) { 
     super.paintComponent(g); 

     while (!model.runExperiment(1)) { 
      for (int y = 0; y < model.getIndexSize(); y++) { 
       for (int x = 0; x < model.getIndexSize(); x++) { 
        if (model.getMatrixValue(x, y)) { 
         g.drawOval(x, y, 2, 2); 
        } 
       } 
      } 
     } 
    } 
}