2009-12-16 120 views
1

JAVA- 嗨, 我在写一个扫雷程序(第一个biggie),我真的陷入了困境。程序本身由两个类组成(一个用于逻辑,一个用于GUI),按照我要遵循的规范。我在这两门课中都做得很好,但还没有完成。但是,我试图从一个类到另一个类测试实现的调用方法,这就是我陷入困境的地方。在GUI类中,每当用户点击一个盒子时,我都试图调用逻辑类中的方法openCell(int x,int y)。逻辑类方法将依次检查广场上是否存在地雷,0或数字,并从GUI类中调用适当的方法。是涉及错误的两种方法如下:NullPointer当从差异类中调用方法时出现异常

GUI CLASS 
public void mouseClicked(MouseEvent e) { 
    for (int x = 0 ; x < width ; x++) { 
     for (int y = 0 ; y < height ; y++) { 
      if (e.getSource() == table[x][y]) {  
       if(e.getButton() == e.BUTTON1) { 
        MinesweeperLogic logicClass = new MinesweeperLogic(); 
        logicClass.isOpen(x, y); // <--------------------------- ERROR 
       }}}}} 

LOGIC CLASS 
boolean openCell(int x, int y) { 
isClicked[x][y] = true; 
    if(mine[x][y] == true && flag[x][y]==false) { 
     return false; 
    } else if(neighborBombs(x, y) > 0 && flag[x][y]==false) { 
     return true; 
    }else { 
      marked = true; 
      return marked; 
    }} 

以下是错误报告我在比赛中收到一旦用户点击了一个盒子(编译代码时它确实抓住它):

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException 
at MinesweeperLogic.isOpen(MinesweeperLogic.java:117) 
at MineSweeperGUI.mouseClicked(MineSweeperGUI.java:126) 
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:253) 
at java.awt.Component.processMouseEvent(Component.java:6266) 
at javax.swing.JComponent.processMouseEvent(JComponent.java:3255) 
at java.awt.Component.processEvent(Component.java:6028) 
at java.awt.Container.processEvent(Container.java:2041) 
at java.awt.Component.dispatchEventImpl(Component.java:4630) 
at java.awt.Container.dispatchEventImpl(Container.java:2099) 
at java.awt.Component.dispatchEvent(Component.java:4460) 
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4574) 
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4247) 
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4168) 
at java.awt.Container.dispatchEventImpl(Container.java:2085) 
at java.awt.Window.dispatchEventImpl(Window.java:2475) 
at java.awt.Component.dispatchEvent(Component.java:4460) 
at java.awt.EventQueue.dispatchEvent(EventQueue.java:599) 
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) 
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) 
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) 
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) 
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) 
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122) 

最后,如果需要,到目前为止,整个(此时不完整)代码为两个类。 (逻辑类中的方法需要根据项目的指令执行特定的操作,并且在逻辑类中必须没有用户交互)。我无法弄清楚究竟是什么导致了错误。任何指导将不胜感激。 (希望这不是很明显,因为我花了最后几个小时试图弄清楚,即使我有流感!)。

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

public class MineSweeperGUI extends JFrame implements ActionListener, MouseListener { 
int width = 10; 
int height = 10; 
JPanel p = new JPanel(); 
JButton[][] table = new JButton[width][height]; 

public void MineSweeper() { 
    MinesweeperLogic logicClass = new MinesweeperLogic(); 
    logicClass.startNewGame(width, height); 
    JButton[] button = new JButton[width*height]; 
    GridLayout layout = new GridLayout (width, height) ; 
    p.setLayout(layout); 
    for(int x = 0 ; x < width ; x++) { 
     for(int y = 0 ; y < height ; y++) { 
      table[x][y] = new JButton(); 
      table[x][y].setPreferredSize(new Dimension(25,25)); 
      table[x][y].addMouseListener (this); 
      p.add(table [x] [y]); 
     } 
    }  
    this.add(p); 
    this.pack(); 
    this.setVisible(true); 
} 


public void mouseClicked(MouseEvent e) { 
    for (int x = 0 ; x < width ; x++) { 
     for (int y = 0 ; y < height ; y++) { 
      if (e.getSource() == table[x][y]) {  
       if(e.getButton() == e.BUTTON1) { 
        MinesweeperLogic logicClass = new MinesweeperLogic(); 
        logicClass.isOpen(x, y); //<-------------------------------------- 
       } 
      } 
     } 
    } 
} 
public void gameover(int x, int y) { 
    table[x][y].setText("*"); 
} 

public static void main(String[]args) { 
    MineSweeperGUI guiClass = new MineSweeperGUI(); 
    guiClass.MineSweeper(); 
}}  


public void actionPerformed(ActionEvent e) { 
} 

public void mouseEntered(MouseEvent e) { 
} 

public void mousePressed(MouseEvent e) { 
} 

public void mouseExited(MouseEvent e) { 
} 

public void mouseReleased(MouseEvent e) { 
} 




public class MinesweeperLogic { 

private int w, h, maxBombs, bombsremaining; 
public int width, height; 
private boolean mine[][]; 
private boolean flag[][]; 
private boolean isClicked[][]; 
private boolean isZero[][]; 
private boolean marked; 



public void startNewGame(int width, int height) { 
    w = width; 
    h = height; 
    flag = new boolean[w][h]; 
    isZero = new boolean[w][h]; 
    isClicked = new boolean[w][h]; 
    mine = new boolean[w][h]; 
    maxBombs =(int) Math.floor (width*height*0.15); 
    bombsremaining = maxBombs; 
    for(int i = 0; i < maxBombs; i++) { 
     int x = (int) (Math.random() * (w)); 
     int y = (int) (Math.random() * (h)); 
     if (mine[x][y] == false) { 
      mine[x][y] = true; 
      isClicked[x][y] = false; 
      flag[x][y] = false; 
     } 
    } 
} 


int getWidth() { 
    return w; 
} 


int getHeight() { 
    return h; 
} 


boolean openCell(int x, int y) { // <--------------------------------------------- 
    //MineSweeperGUI guiClass = new MineSweeperGUI(); 
    isClicked[x][y] = true; 
    if(mine[x][y] == true && flag[x][y]==false) { 
     //guiClass.gameover(x, y); 
     return false; 
    } else if(neighborBombs(x, y) > 0 && flag[x][y]==false) { 
     return true; 
    } else { 
      marked = true; 
      return marked; 
    }} 


boolean markCell(int x, int y) { 
    if(flag[x][y] == true) { 
      flag[x][y] = false; 
      isClicked[x][y] = false; 
      bombsremaining++; 
      marked = false; 
      return marked; 
     } else { 
      flag[x][y] = true; 
      isClicked[x][y] = true; 
      bombsremaining--; 
       if(mine[x][y]==true) { 
        return true; 
       } else { 
        return false; 
       } 
      } 
     } 


boolean isOpen(int x, int y) { 
    if(isClicked[x][y] == false) { 
     return false; 
     } else { 
      return true; 
     } 
} 


boolean isMarked(int x, int y) { 
    if(flag[x][y] == true) { 
     return true; 
     } else { 
      return false; 
     } 
    } 


    int getValue(int x, int y) { 
     if(mine[x][y] == true) { 
      return -1; 
     } else { 
      return neighborBombs(x, y); 
     } 
    } 


    private int neighborBombs(int x, int y) { // checks surrounding 8 squares for number of bombs 
     int surBombs = 0; 
      for (int q = x - 1 ; q <= x + 1 ; q++) { 
       for (int w = y - 1 ; w <= y + 1 ; w++) { 
        while (true) { 
         if (q < 0 || w < 0 || q >= w || w >= h) { 
          break; 
         } 
         if (mine[q][w] == true) { 
          surBombs++; 
          break; 
         } 
        } 
       } 
      } 
     return surBombs; 
     } 
    } 

回答

11

怎么样:

  1. 看看你的异常堆栈跟踪的第一行,看看哪一类和哪条线路出现问题
  2. 转到该行,看看哪些对象也可能会被“空”在这个位置
  3. 找出原因就是空不具有价值的对象assgined
  4. 如果有一个以上的对象,可能为空,你可以System.out.println()他们,看到whchi一个。
+1

虽然这将有助于修复NullPointerException,但所涉及的代码非常错误,以至于无法让他更接近实际的扫雷游戏。 – tster 2009-12-16 20:30:14

+1

step by step :) – Bozho 2009-12-16 20:32:12

+2

学习如何使用调试器比System.out.println – rob 2009-12-16 20:48:57

0

这将有助于知道逻辑类中的行号为117。我的猜测是mine,mine[x],flaggedflagged[x]为空。

这就是说,“循环遍历整个桌子以查看哪个被点击”的技巧并没有引起我特别的启发。

编辑:其实,问题是,isOpen数组为空,因为你只是实例化类。

编辑2:好的,所以它是我最初列出的之一。我的猜测是都是,因为你只是实例化了类,而且它使用了默认的无所作为的构造函数。

+0

有一个彩色的箭头指向第一部分代码中可能是第117行的东西。 – 2009-12-16 20:27:57

+1

除了它不指向那条线。 – 2009-12-16 20:29:49

+0

它完全没有指向那条线,它实际上指向了*完全不同的类*中的一条线。 – 2009-12-16 20:30:57

2

数组(标志,isZero,isClicked)未初始化,在尝试使用它们时为空。您需要GUI类来包含逻辑类的实例,并始终使用相同的实例。否则,每个GUI动作都将在不同的游戏中发生!

+0

我同意。您每次单击鼠标时都会创建一个MinesweeperLogic的新实例。您需要坚持在MineSweeper()方法中创建的实例。 – goatlinks 2009-12-16 21:19:59

4

你的堆栈跟踪告诉你这一点:

异常在线程 “AWT-EventQueue的-0” 显示java.lang.NullPointerException 在MinesweeperLogic.isOpen(MinesweeperLogic.java:117)

所以您可以转到第117行并确定哪些引用可能为空。 (看起来你在堆栈跟踪之后在117处添加了一行,然后将新行注释掉了,所以我要在这里出去,并说堆栈跟踪实际上是指现在称为第118行:isClicked[x][y] = true;)在这种情况下,唯一可能为空的是isClicked[][]

深入挖掘,我们可以看到你在startNewGame()中初始化isClicked,但显然这个实例正在迷失。发生这种情况的原因有两个:首先,构造函数中的logicClass超出了范围,因为它不是该类的成员。其次(这可能是修复第一个问题的失败尝试),在mouseClicked中,您将创建一个新的MinesweeperLogic(以及新创建的空isClicked),而不是使用之前在您的MineSweeper()构造函数中创建的那个。

您应该对清理代码做几个其他的重构,但将logicClass作为成员并删除重复的实例化应该解决当前的问题。

它可能对您有帮助,使用调试器,并自己逐步解决问题,以准确了解发生了什么。

0

你说,在的mouseClicked()方法时发生错误,但是堆栈跟踪显示不同:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException 
at MinesweeperLogic.isOpen(MinesweeperLogic.java:117) 
at MineSweeperGUI.mouseClicked(MineSweeperGUI.java:126) 

这是说,NPE发生在MineSweeperLogic的117线。使用该行上的调试器,或者插入print语句来计算出null,然后可以找出原因。

相关问题