我正在开发控制器以制作数独游戏。当您运行我的 SudokuMain.java 文件,然后单击页面顶部的“文件”,然后选择“新游戏”时,出现异常:
线程“AWT-EventQueue-0”中的异常 java.lang.NullPointerException
我有一个用于“新游戏”的 ActionListener 来创建一个名为“创建板”的 JDialog 对象,并提示用户输入“每个区域的行”和“每个区域的列”并按“创建板”,或者按“取消”并取消它。
我不确定我做错了什么,但我觉得问题出在内部类 MenuAtTop 上。任何帮助表示赞赏!
// Allow short name access to following classes
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
public class SudokuMain extends JComponent {
public static void main(String[] args) {
new SudokuMain();
}
private SudokuBase board;
private SudokuView view;
private JFrame win;
private JPanel center;
private JPanel west;
private JPanel east;
private JPanel cells;
private final Dialog1 setWin1;
public SudokuMain() {
// start game
view = new SudokuView(makeBoard());
board = makeBoard();
win = new JFrame("Sudoku");
center = new JPanel();
west = new JPanel();
east = new JPanel();
// "player" cells for current Sudoku board
cells = new SetSymbols(view);
// the 1st set-up window
setWin1 = new Dialog1(this, "New Game", true);
// create menu bar
MenuAtTop menuBar = new MenuAtTop(this);
win.setJMenuBar(menuBar);
win.setLayout(new BorderLayout());
view.setSelected(1, 1);
west.setLayout(new BorderLayout());
east.setLayout(new BorderLayout());
center.setLayout(new FlowLayout());
west.add(cells);
east.add(view, BorderLayout.CENTER);
center.add(west);
center.add(east);
win.add(center);
win.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
win.pack();
win.setVisible(true);
}
class SudokuControlButton extends JPanel {
private int row;
private int col;
// row of selected cell
private int selRow;
// column of selected cell
private int selCol;
// the value that corresponds with the desired symbol
private int value;
/**
* Constructs SudokuControlButton object; the graphic "button"
* to control the board.
*/
public SudokuControlButton(final SudokuView view) {
setPreferredSize(new Dimension(40, 40));
setBackground(Color.LIGHT_GRAY);
//value = 0;
addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent e) {
selRow = view.getSelectedRow();
selCol = view.getSelectedColumn();
if(!board.isGiven(selRow, selCol)) {
board.setValue(selRow, selCol, value);
view.repaint();
} else { // have system beep sound
getToolkit().beep();
}
repaint();
}
public void mouseEntered(MouseEvent e){
// set to "highlighted" color
setBackground(Color.WHITE);
repaint();
}
public void mouseExited(MouseEvent e){
// set to default color
setBackground(Color.LIGHT_GRAY);
repaint();
}
public void mousePressed(MouseEvent e){
// set to "active" color
setBackground(Color.YELLOW);
repaint();
}
public void mouseReleased(MouseEvent e){
}
});
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
switch(value) {
case 0:
drawSymbol(g, 0);
break;
case 1:
drawSymbol(g, 1);
break;
case 2:
drawSymbol(g, 2);
break;
case 3:
drawSymbol(g, 3);
break;
case 4:
drawSymbol(g, 4);
break;
case 5:
drawSymbol(g, 5);
break;
case 6:
drawSymbol(g, 6);
break;
case 7:
drawSymbol(g, 7);
break;
case 8:
drawSymbol(g, 8);
break;
case 9:
drawSymbol(g, 9);
break;
case 10:
drawSymbol(g, 10);
break;
case 11:
drawSymbol(g, 11);
break;
case 12:
drawSymbol(g, 12);
break;
}
}
/**
* This method draws the symbol that corresponds with
* the specified value (0-12).
*
* @param g The drawing mechanism.
* @param value The specified value.
*/
public void drawSymbol(Graphics g, int value) {
if(value < 0 || value > 12) {
String msg = "Value cannot be less than 1 or greater than 12.";
throw new IllegalArgumentException(msg);
}
// enable drawing with "thick" lines
Graphics2D g2 = (Graphics2D) g;
g2.setStroke(new BasicStroke(3));
switch(value) {
case 0:
// draw borders
g.drawRect(0, 0, 50, 50);
break;
case 1:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g2.drawLine(5, 5, 5, 45);
break;
case 2:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g2.drawLine(5, 5, 5, 45);
g2.drawLine(10, 5, 10, 45);
break;
case 3:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g2.drawLine(5, 5, 5, 45);
g2.drawLine(10, 5, 10, 45);
g2.drawLine(15, 5, 15, 45);
break;
case 4:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g2.drawLine(5, 5, 5, 45);
g2.drawLine(10, 5, 10, 45);
g2.drawLine(15, 5, 15, 45);
g2.drawLine(20, 5, 20, 45);
break;
case 5:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g2.drawLine(5, 5, 5, 45);
g2.drawLine(10, 5, 10, 45);
g2.drawLine(15, 5, 15, 45);
g2.drawLine(20, 5, 20, 45);
g2.drawLine(25, 5, 25, 45);
break;
case 6:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g2.drawLine(5, 5, 5, 45);
g2.drawLine(10, 5, 10, 45);
g2.drawLine(15, 5, 15, 45);
g2.drawLine(20, 5, 20, 45);
g2.drawLine(25, 5, 25, 45);
g2.drawLine(30, 5, 30, 45);
break;
case 7:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g2.drawLine(5, 5, 5, 20);
g2.drawLine(10, 5, 10, 20);
g2.drawLine(15, 5, 15, 20);
g2.drawLine(20, 5, 20, 20);
g2.drawLine(25, 5, 25, 20);
g2.drawLine(30, 5, 30, 20);
g2.drawLine(5, 30, 5, 45);
break;
case 8:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g2.drawLine(5, 5, 5, 20);
g2.drawLine(10, 5, 10, 20);
g2.drawLine(15, 5, 15, 20);
g2.drawLine(20, 5, 20, 20);
g2.drawLine(25, 5, 25, 20);
g2.drawLine(30, 5, 30, 20);
g2.drawLine(5, 30, 5, 45);
g2.drawLine(10, 30, 10, 45);
break;
case 9:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g2.drawLine(5, 5, 5, 20);
g2.drawLine(10, 5, 10, 20);
g2.drawLine(15, 5, 15, 20);
g2.drawLine(20, 5, 20, 20);
g2.drawLine(25, 5, 25, 20);
g2.drawLine(30, 5, 30, 20);
g2.drawLine(5, 30, 5, 45);
g2.drawLine(10, 30, 10, 45);
g2.drawLine(15, 30, 15, 45);
break;
case 10:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g.drawLine(5, 5, 5, 20);
g.drawLine(10, 5, 10, 20);
g.drawLine(15, 5, 15, 20);
g.drawLine(20, 5, 20, 20);
g.drawLine(25, 5, 25, 20);
g.drawLine(30, 5, 30, 20);
g.drawLine(5, 30, 5, 45);
g.drawLine(10, 30, 10, 45);
g.drawLine(15, 30, 15, 45);
g.drawLine(20, 30, 20, 45);
break;
case 11:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g.drawLine(5, 5, 5, 20);
g.drawLine(10, 5, 10, 20);
g.drawLine(15, 5, 15, 20);
g.drawLine(20, 5, 20, 20);
g.drawLine(25, 5, 25, 20);
g.drawLine(30, 5, 30, 20);
g.drawLine(5, 30, 5, 45);
g.drawLine(10, 30, 10, 45);
g.drawLine(15, 30, 15, 45);
g.drawLine(20, 30, 20, 45);
g.drawLine(25, 30, 25, 45);
break;
case 12:
// draw borders
g.drawRect(0, 0, 50, 50);
// draw symbol
g.drawLine(5, 5, 5, 20);
g.drawLine(10, 5, 10, 20);
g.drawLine(15, 5, 15, 20);
g.drawLine(20, 5, 20, 20);
g.drawLine(25, 5, 25, 20);
g.drawLine(30, 5, 30, 20);
g.drawLine(5, 30, 5, 45);
g.drawLine(10, 30, 10, 45);
g.drawLine(15, 30, 15, 45);
g.drawLine(20, 30, 20, 45);
g.drawLine(25, 30, 25, 45);
g.drawLine(30, 30, 30, 45);
break;
}
}
}
class MenuAtTop extends JMenuBar implements ActionListener{
private SudokuMain main;
private JMenu fileMenu;
private JMenuItem newGame;
private JDialog createNewWin;
public MenuAtTop(final SudokuMain m) {
fileMenu = new JMenu("File");
add(fileMenu);
newGame = new JMenuItem("New Game");
newGame.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
ActionEvent.CTRL_MASK));
fileMenu.add(newGame);
newGame.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
setEnabled(false);
createNewWin = new Dialog1(main, "Create New Board", true);
}
}
class Dialog1 extends JDialog {
private JTextField rows;
private JTextField cols;
private JButton createBoard;
private JButton cancel;
private JLabel rowLabel;
private JLabel colLabel;
private JLabel errorMes;
private JPanel center;
private JPanel north;
private JDialog setUpWin2;
/**
* Constructs Dialog1 object.
*
* @param win The window containing the dialog box.
* @param header The title of dialog box.
* @param modal Whether dialog box is modal or not.
*/
public Dialog1(final SudokuMain win, String header, boolean modal) {
// call superclass constructor
super();
// instantiate and bind to references
rows = new JTextField(2);
cols = new JTextField(2);
createBoard = new JButton("Create Board");
cancel = new JButton("Cancel");
rowLabel = new JLabel("Rows per region: ");
colLabel = new JLabel("Columns per region: ");
errorMes = new JLabel();
north = new JPanel(new FlowLayout());
center = new JPanel(new FlowLayout());
// set characteristics
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
setTitle(header);
setModal(modal);
setLayout(new BorderLayout());
// set characteristics of error message
errorMes.setForeground(Color.RED);
errorMes.setFont(new Font("Arial", Font.ITALIC, 12));
errorMes.setVisible(false);
cancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
createBoard.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int newRows;
int newCols;
int newSize;
try{
newRows = Integer.parseInt(rows.getText());
newCols = Integer.parseInt(cols.getText());
} catch (NumberFormatException exc) {
newRows = 0;
newCols = 0;
}
newSize = newRows * newCols;
// input validation
if(newSize <= 0 && newSize > 12) {
errorMes.setText("Rows times columns cannot be greater than 12!");
errorMes.setVisible(true);
pack();
} else{ // valid input
errorMes.setVisible(false);
setVisible(false);
setUpWin2 = new Dialog2(win, "New Sudoku", newRows, newCols, true);
}
}});
// place error message in the center
center.add(errorMes);
// place labels for rows and columns at the top
north.add(rowLabel);
north.add(rows);
north.add(colLabel);
north.add(cols);
add(center, BorderLayout.CENTER);
add(north, BorderLayout.NORTH);
pack();
if(!win.win.isVisible()) {
dispose();
}
}
}
class Dialog2 extends JDialog {
private SudokuView view;
private JPanel panel;
private JPanel northPanel;
private JPanel cells;
private JButton setGivens;
private JButton cancel;
/**
* Constructs Dialog2 object.
*
* @param win The window containing the dialog box.
* @param header The title of the dialog box.
* @param rows the rows to the new SudokuBoard to be constructed in the dialog box
* @param cols the columns to the new SudokuBoard to be constructed in the dialog box
* @param modal boolean value for whether the box is modal or not
*/
public Dialog2(final SudokuMain mainWin, String header, int rows, int cols,
boolean modal) {
// call superclass constructor
super();
// instantiate and bind to references
view = new SudokuView(new SudokuBoard(rows, cols));
panel = new JPanel();
northPanel = new JPanel();
setGivens = new JButton("Set Givens");
cancel = new JButton("Cancel");
cells = new SetSymbols(view);
// set up characteristics
setTitle(header);
setModal(modal);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLayout(new FlowLayout());
panel.setLayout(new BorderLayout());
northPanel.setLayout(new FlowLayout());
setGivens.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// set "given" cells
makeBoard().fixGivens();
// have window refer to new board
west.remove(mainWin.view);
mainWin.east.remove(mainWin.cells);
mainWin.view = view;
mainWin.cells = cells;
mainWin.west.add(mainWin.view);
mainWin.east.add(mainWin.cells);
setVisible(false);
}});
cancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setVisible(false);
}});
// place buttons at the top
northPanel.add(setGivens);
northPanel.add(cancel);
panel.add(view, BorderLayout.CENTER);
panel.add(northPanel, BorderLayout.NORTH);
add(panel);
add(cells);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
pack();
setVisible(true);
}
}
class SetSymbols extends JPanel {
// temporary board to help create graphic "buttons"
private SudokuBoard tempBd;
/**
* Constructs SetSymbols object.
* @param view The SudokuView object for SetSymbols.
*/
public SetSymbols(final SudokuView view) {
// instantiate and bind to reference
tempBd = new SudokuBoard(1, board.getBoardSize() + 1);
setLayout(new GridLayout((tempBd.getBoardSize())/2 + 1, 2));
for(int colCell = 0; colCell < tempBd.getBoardSize(); colCell++) {
// cannot be changed after set/instantiated
final int value = colCell;
final JPanel cell = new JPanel();
final Color defaultColor = cell.getBackground();
// set characteristics
cell.setBorder(BorderFactory.createLineBorder(Color.BLACK));
// set value for each graphic "button"
tempBd.setValue(0, colCell, colCell);
// add the appropriate symbol to each graphic "button"
cell.add(view.new SudokuCell(0, colCell, tempBd));
cell.addMouseListener(new MouseListener() {
// whether inside graphic "button" or not
boolean insideCell;
public void mouseClicked(MouseEvent e) {
int selRow = view.getSelectedRow();
int selCol = view.getSelectedColumn();
if(!board.isGiven(selRow, selCol)) {
board.setValue(selRow, selCol, value);
view.repaint();
}
else { // have system beep sound
cell.getToolkit().beep();
}
}
public void mouseEntered(MouseEvent e) {
insideCell = true;
// set to "highlighted" color
cell.setBackground(Color.WHITE);
view.repaint();
}
public void mouseExited(MouseEvent e) {
insideCell = false;
// set to default color
cell.setBackground(defaultColor);
view.repaint();
}
public void mousePressed(MouseEvent e) {
// set to "active" color
cell.setBackground(Color.YELLOW);
view.repaint();
}
public void mouseReleased(MouseEvent e) {
if(insideCell) {
cell.setBackground(Color.YELLOW);
}
else { // outside of symbol's cell
cell.setBackground(defaultColor);
}
view.repaint();
}
});
// add graphic "button"
add(cell);
}
// handle possible "empty" graphic "button"
if(tempBd.getBoardSize() % 2 != 0) {
JPanel empty = new JPanel();
empty.setBackground(Color.LIGHT_GRAY);
empty.setBorder(BorderFactory.createLineBorder(Color.BLACK));
add(empty);
}
}
}
public static SudokuBase makeBoard() {
SudokuBase board = new SudokuBoard(2, 3);
board.setValue(0, 3, 6);
board.setValue(0, 5, 1);
board.setValue(1, 2, 4);
board.setValue(1, 4, 5);
board.setValue(1, 5, 3);
board.setValue(2, 3, 3);
board.setValue(3, 2, 6);
board.setValue(4, 0, 2);
board.setValue(4, 1, 3);
board.setValue(4, 3, 1);
board.setValue(5, 0, 6);
board.setValue(5, 2, 1);
board.fixGivens();
return board;
}
}