2010-12-04 122 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); 
        } 
       } 
      } 
     } 
    } 
}