0

我正在创建数独游戏,并尝试提供保存、另存为和打开游戏的选项。我正在使用 JFileChooser 来执行此操作。我可以保存(或“另存为”),但是当我尝试打开保存的文件时,出现错误。我是编程新手,我希望有人能发现问题并教育我在保存时如何阅读数独板的内容(以及打开时如何处理重新创建数独板文件)。我听说有一种更简单的方法可以使用 InputStream/OutputStream 而不是 Reader/Writer...

这是我实现这个的内部类的代码(我不知道是否有办法在不超过此文本框字符限制的情况下发布我的整个类。):

  // this inner class provides a JMenuBar object at the top of
  // the board
  class MenuAtTop extends JMenuBar implements ActionListener{

    // SudokuMain2 object we are dealing with
    private SudokuMain2 main;

    // the "File" menu
    private JMenu fileMenu;
    // the "New Game" option
    private JMenuItem newGame;
    // the "Open" option
    private JMenuItem open;
    // the "Save" option
    private JMenuItem save;
    // the "Save As" option
    private JMenuItem saveAs;
    // the "Reset" option
    private JMenuItem reset;
    // the "Quit" option
    private JMenuItem quit;

    // the ability to choose files
    private JFileChooser choose;

    // the saved file
//    // compiler would not allow "static" keyword
    private File fileSaved = null;

    private Object opener;

    // JDialog object to create a dialog box to prompt
    // user for new game information
    private JDialog createNewWin; 

    /**
     * Constructs MenuAtTop object.
     * 
     * @param m The SudokuMain2 object to be referred to.
     */
    public MenuAtTop(final SudokuMain2 m) {

      main = m;

      opener = null;
      choose = new JFileChooser();

      // instantiate and bind to reference
      fileMenu = new JMenu("File");
      add(fileMenu);

      // instantiate and bind to reference
      newGame = new JMenuItem("New Game");
      newGame.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
                                                    ActionEvent.CTRL_MASK));
      fileMenu.add(newGame);
      newGame.addActionListener(this);

      open = new JMenuItem("Open");
      open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
                                                 ActionEvent.CTRL_MASK));
      fileMenu.add(open);
      // add action listener to "Open" option
      open.addActionListener(this);

      save = new JMenuItem("Save");
      save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
                                                 ActionEvent.CTRL_MASK));
      fileMenu.add(save);
//      //save.setEnabled(false);
      // add action listener to "Save" option
      save.addActionListener(this);

      saveAs = new JMenuItem("Save As");
      saveAs.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
                                                   ActionEvent.CTRL_MASK));
      fileMenu.add(saveAs);
      // add action listener to "Save As" option
      saveAs.addActionListener(this);

      reset = new JMenuItem("Reset");
      reset.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,
                                                  ActionEvent.CTRL_MASK));
      fileMenu.add(reset);
      // add action listener to "Reset" option
      reset.addActionListener(this);

      quit = new JMenuItem("Quit");
      quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
                                                 ActionEvent.CTRL_MASK));
      fileMenu.add(quit);
      // add action listener to "Quit" option
      quit.addActionListener(this);

    }

    public void actionPerformed(ActionEvent e) {
      if(e.getSource().equals(quit)) {
        closePrompt();
        //main.win.dispose();
      }
      else if(e.getSource().equals(reset)) {
        int n = JOptionPane.showConfirmDialog(main.win, 
                                              "Any player values will" +
                                              " be lost. Proceed?",
                                              "Warning!", 2);
        if(n == JOptionPane.OK_OPTION) {
          main.board.reset();

          main.view.repaint();
        }
      }
      else if(e.getSource().equals(saveAs)) {
        saveAs();
      }
      else if(e.getSource().equals(save)) {
        if(fileSaved == null) {
          saveAs();
        }
        else {
          try {
            board.writeToStream(new FileOutputStream(fileSaved));
//            main.board.setDirty(false);
          } catch (Exception ex) {
            JOptionPane.showMessageDialog(main.win, "Error saving file.");
          }
        }
      }

      else if(e.getSource().equals(open)) {

        int returnVal = choose.showOpenDialog(main.win);
        if(returnVal == JFileChooser.APPROVE_OPTION) {
          boolean error = false;
          File openFile = choose.getSelectedFile();

          try {
            FileInputStream fin = new FileInputStream(openFile);
            ObjectInputStream ois = new ObjectInputStream(fin);
            opener = ois.readObject();
          } catch (Exception ex) {
            JOptionPane.showMessageDialog(main.win, "Error opening file.");
            error = true;
          }

          if(opener != null && opener instanceof SudokuBase){
            main.west.remove(main.symbols);
            main.east.remove(main.view);
            //add in state information for new board
            main.south.remove(main.rowColRegStates);

            main.view =  new SudokuView((SudokuBase) opener);
            main.symbols = new SetSymbols(main.view);
            //add in state information for new board
            main.rowColRegStates = new ShowStates(main.view);

            main.west.add(main.symbols);
            main.east.add(main.view);
            //add in state information for new board
            main.south.add(main.rowColRegStates);

            main.win.requestFocus();

            fileSaved = openFile;
//            main.board.setDirty(false);
          } else {
            if(error) {
              JOptionPane.showMessageDialog(main.win, " Incorrect file type!");
            }
          }
        }
        // else: user cancelled
      }
      else if(e.getSource().equals(newGame)) {
        setEnabled(false);
        // create dialog box prompting for the new board information
        createNewWin = new Dialog1(main, "Create New Board", true);
        // make it visible
        createNewWin.setVisible(true);

        fileSaved = null;
      }
    }

    // This method prompts the user to choose a file to save to,
    // and then saves the file.
    private int saveAs() {
      boolean saveError;
      int rtn = choose.showSaveDialog(main.win);

      if(rtn == JFileChooser.APPROVE_OPTION) {
        saveError = false;
        File fileSaveAs = choose.getSelectedFile();
        try {
          board.writeToStream(new FileOutputStream(fileSaveAs));
        } catch (Exception e) {
          JOptionPane.showMessageDialog(main.win, "Error saving file.");
          saveError = true;
        }

        if(!saveError) {
          fileSaved = fileSaveAs;
//          main.board.setDirty(false);
        }
      }

      return rtn;

    }

    /**
     * Asks the user if they want to save before closing if changes were made.
     */
    private void closePrompt() {
      if(true) {  //board.isDirty()) {
        int n = JOptionPane.showConfirmDialog(main.win, "Save game?");
        if(n == JOptionPane.YES_OPTION) {
          int saved = saveAs();
          if(saved != JFileChooser.CANCEL_OPTION){
            main.win.dispose();
          }
        }
        else if(n == JOptionPane.NO_OPTION) {
          main.win.dispose();
        }
      }
      else
        main.win.dispose();
    }

  }
4

2 回答 2

0

这是 SudokuMain 类的第一部分(我不小心在 MenuAtTop 中放了“SudokuMain2”而不是“SudokuMain”,所以忽略 2):

// Allow short name access to following classes
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.io.*;

public class SudokuMain extends JComponent {

  /**
   * The application method.
   * 
   * @param args The command-line arguments.
   */
  public static void main(String[] args) {
    new SudokuMain();
  }

  // this field refers to the SudokuBase class to access information
  // of the board.
  private SudokuBase board;
  // this field refers to SudokuView object to access its information
  // and provide output
  private SudokuView view;

  // the window all the components are contained in
  private JFrame win;
  // center JPanel object in window
  private JPanel center;
  // left JPanel object in window
  private JPanel west;
  // right JPanel object in window
  private JPanel east;
  // bottom JPanel object in window
  private JPanel south;

  // JPanel object to hold graphic "buttons"
  private JPanel symbols;
  // JPanel object to show "states" of Sudoku board
  private JPanel rowColRegStates;

  // the first set-up window (cannot be changed once
  // instantiated)
  private final Dialog1 setWin1;

  /**
   * Constructs SudokuMain object.
   */
  public SudokuMain() {

    // start game
    board = makeBoard();
    view = new SudokuView(board);

    win = new JFrame("Sudoku Game");
    center = new JPanel();
    west = new JPanel();
    east = new JPanel();
    south = new JPanel();

    // graphic "buttons" for current Sudoku board
    symbols = new SetSymbols(view);
    // "states" of current Sudoku board
    rowColRegStates = new ShowStates(view);

    // the first set-up window
    setWin1 = new Dialog1(this, "New Game", true);

    // create menu bar
    final MenuAtTop menuBar = new MenuAtTop(this);
    win.setJMenuBar(menuBar);

    // display game mode
    JLabel mode = new JLabel("Normal Play Mode");
    mode.setHorizontalAlignment(JLabel.CENTER);
    Font modeFont = new Font("Arial", Font.BOLD, 14);
    mode.setFont(modeFont);

//    // set selected cell at (0, 0)
//    view.setSelected(0, 0);

    // add window focus listener
    win.addWindowFocusListener(new WindowFocusListener() {

      public void windowGainedFocus(WindowEvent e) {
        win.pack();
        // set selected cell at (0, 0)
        view.setSelected(0, 0);
      }

      public void windowLostFocus(WindowEvent e) {
      }
    });

    // add window listener
    win.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        menuBar.closePrompt();
      }
    });

    win.setLayout(new BorderLayout());
    west.setLayout(new BorderLayout());
    east.setLayout(new BorderLayout());
    center.setLayout(new FlowLayout());

    west.add(symbols);
    east.add(view, BorderLayout.CENTER);
    south.add(rowColRegStates);
    center.add(west);
    center.add(east);

    win.add(south, BorderLayout.NORTH);
    win.add(center, BorderLayout.CENTER);
    win.add(mode, BorderLayout.SOUTH);

    win.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    win.pack();
    win.setVisible(true);

  }

  // this inner class constructs graphic "buttons" to set desired
  // cells of board
  class SudokuControlButton extends JPanel {

    // 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.
     * 
     * @param view The SudokuView object to be controlled.
     * @param v The value that corresponds to the desired symbol.
     */
    public SudokuControlButton(final SudokuView view, int v) {
      // set characteristics of graphic "button"
      setPreferredSize(new Dimension(50, 50));
      setBackground(Color.LIGHT_GRAY);

      value = v;

      addMouseListener(new MouseListener() {

        /**
         * This method selects a "button" and puts it in focus when the mouse
         * is clicked on it.
         * 
         * @param event Captures information on the mouse button being
         *              clicked (pressed and released) on a component.
         */
        public void mouseClicked(MouseEvent e) {
          selRow = view.getSelectedRow();
          selCol = view.getSelectedColumn();

          if(!board.isGiven(selRow, selCol)) {
            board.setValue(selRow, selCol, value);
            view.new SudokuCell(selRow, selCol, board);
            // set to "highlighted" color
            setBackground(Color.WHITE);
            view.repaint();
          }
          else {  // have system beep sound
            getToolkit().beep();
          }

          repaint();
        }

        /**
         * This method handles behavior when the mouse enters a graphic
         * "button".
         * 
         * @param event Captures information on the mouse button being
         *              entered over a component.
         */ 
        public void mouseEntered(MouseEvent e){
          // set to "highlighted" color
          setBackground(Color.WHITE);

          repaint();
        }

        /**
         * This method handles behavior when the mouse exits a graphic
         * "button".
         * 
         * @param event Captures information on the mouse button being
         *              exited from a component.
         */
        public void mouseExited(MouseEvent e){
          // set to default color
          SudokuControlButton button = (SudokuControlButton) e.getSource();

          setBackground(Color.LIGHT_GRAY);

          repaint();
        }

        /**
         * This method handles behavior when the mouse is pressed on a
         * graphic "button".
         * 
         * @param event Captures information on the mouse button being
         *              pressed on a component.
         */
        public void mousePressed(MouseEvent e){
          // set to "active" color
          setBackground(Color.YELLOW);

          repaint();
        }

        /**
         * This method handles behavior when the mouse is released on a
         * graphic "button".
         * 
         * @param e Captures information on the mouse button being
         *              released on a component.
         */
        public void mouseReleased(MouseEvent e){
        }

      });

    }

    /**
     * This method draws the graphic "button" associated with
     * each numeric value, 0 to 12.
     * 
     * @param g The drawing mechanism.
     */
    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 0 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;
      }

    }

  }

  // this inner class provides a JMenuBar object at the top of
  // the board
  class MenuAtTop extends JMenuBar implements ActionListener{

    // SudokuMain object we are dealing with
    private SudokuMain main;

    // the "File" menu
    private JMenu fileMenu;
    // the "New Game" option
    private JMenuItem newGame;
    // the "Open" option
    private JMenuItem open;
    // the "Save" option
    private JMenuItem save;
    // the "Save As" option
    private JMenuItem saveAs;
    // the "Reset" option
    private JMenuItem reset;
    // the "Quit" option
    private JMenuItem quit;

    // the ability to choose files
    private JFileChooser choose;

    // the saved file
//    // compiler would not allow "static" keyword
    private File fileSaved = null;

    private Object opener;

    // JDialog object to create a dialog box to prompt
    // user for new game information
    private JDialog createNewWin; 

    /**
     * Constructs MenuAtTop object.
     * 
     * @param m The SudokuMain object to be referred to.
     */
    public MenuAtTop(final SudokuMain m) {

      main = m;

      opener = null;
      choose = new JFileChooser();

      // instantiate and bind to reference
      fileMenu = new JMenu("File");
      add(fileMenu);

      // instantiate and bind to reference
      newGame = new JMenuItem("New Game");
      newGame.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
                                                    ActionEvent.CTRL_MASK));
      fileMenu.add(newGame);
      newGame.addActionListener(this);

      open = new JMenuItem("Open");
      open.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O,
                                                 ActionEvent.CTRL_MASK));
      fileMenu.add(open);
      // add action listener to "Open" option
      open.addActionListener(this);

      save = new JMenuItem("Save");
      save.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
                                                 ActionEvent.CTRL_MASK));
      fileMenu.add(save);
      // add action listener to "Save" option
      save.addActionListener(this);

      saveAs = new JMenuItem("Save As");
      saveAs.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A,
                                                   ActionEvent.CTRL_MASK));
      fileMenu.add(saveAs);
      // add action listener to "Save As" option
      saveAs.addActionListener(this);

      reset = new JMenuItem("Reset");
      reset.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R,
                                                  ActionEvent.CTRL_MASK));
      fileMenu.add(reset);
      // add action listener to "Reset" option
      reset.addActionListener(this);

      quit = new JMenuItem("Quit");
      quit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q,
                                                 ActionEvent.CTRL_MASK));
      fileMenu.add(quit);
      // add action listener to "Quit" option
      quit.addActionListener(this);

    }

    public void actionPerformed(ActionEvent e) {

      if(e.getSource().equals(newGame)) {

        setEnabled(false);
        // create dialog box prompting for the new board information
        createNewWin = new Dialog1(main, "Create New Board", true);
        // make it visible
        createNewWin.setVisible(true);

        fileSaved = null;

      } else if(e.getSource().equals(open)) {

        int returnVal = choose.showOpenDialog(main.win);
        if(returnVal == JFileChooser.APPROVE_OPTION) {
          boolean error = false;
          File openFile = choose.getSelectedFile();

          try {
            FileInputStream fin = new FileInputStream(openFile);
            ObjectInputStream ois = new ObjectInputStream(fin);
            opener = ois.readObject();
          } catch (Exception exc) {
            JOptionPane.showMessageDialog(main.win, "Error opening file.");
            error = true;
          }

          // "opener" reads something and it is of type SudokuBase
          if(opener != null && opener instanceof SudokuBase){
            main.west.remove(main.symbols);
            main.east.remove(main.view);
            main.south.remove(main.rowColRegStates);

            main.view =  new SudokuView((SudokuBase) opener);
            main.symbols = new SetSymbols(main.view);
            main.rowColRegStates = new ShowStates(main.view);

            main.west.add(main.symbols);
            main.east.add(main.view);
            main.south.add(main.rowColRegStates);

            main.win.requestFocus();

            fileSaved = openFile;
          } else {
            if(error) {
              JOptionPane.showMessageDialog(main.win, "Incorrect file type.");
            }
          }
        }

      } else if(e.getSource().equals(save)) {

        if(fileSaved == null) {
          saveAsPrompt();
        } else {
          try {
            board.writeToStream(new FileOutputStream(fileSaved));
          } catch (Exception exc) {
            JOptionPane.showMessageDialog(main.win, "Error saving file.");
          }
        }

      } else if(e.getSource().equals(saveAs)) {
        saveAsPrompt();
      } else if(e.getSource().equals(reset)) {

        int n = JOptionPane.showConfirmDialog(main.win, 
                                              "Any player values will" +
                                              " be lost. Proceed?",
                                              "Warning!", 2);
        if(n == JOptionPane.OK_OPTION) {
          main.board.reset();
          main.view.repaint();
        }

      } else if(e.getSource().equals(quit)) {
        closePrompt();
      }

    }

    // This method prompts the user to choose a file to save to,
    // and then saves the file.
    private int saveAsPrompt() {
      boolean saveError;
      int rtn = choose.showSaveDialog(main.win);

      if(rtn == JFileChooser.APPROVE_OPTION) {
        saveError = false;
        File fileSaveAs = choose.getSelectedFile();
        try {
          board.writeToStream(new FileOutputStream(fileSaveAs));
        } catch (Exception e) {
          JOptionPane.showMessageDialog(main.win, "Error saving file.");
          saveError = true;
        }

        if(!saveError) {
          fileSaved = fileSaveAs;
        }
      }

      return rtn;

    }

    // This method prompts the user whether they want to save before
    // closing, only if changes occurred.
    private void closePrompt() {
      if(true) {
        int n = JOptionPane.showConfirmDialog(main.win, "Save game?");
        if(n == JOptionPane.YES_OPTION) {
          int saved = saveAsPrompt();
          if(saved != JFileChooser.CANCEL_OPTION){
            main.win.dispose();
          }
        } else if(n == JOptionPane.NO_OPTION) {
          main.win.dispose();
        }
      }
      else { // no changes were made
        main.win.dispose();
      }
    }

  }

...

于 2013-07-26T03:43:43.503 回答
0

... // SudokuMain 类的第二部分也是最后一部分

  // this inner class provides a dialog box to prompt the user
  // for new board information
  class Dialog1 extends JDialog {

    // rows for new game
    private JTextField rows;
    // cols for new game
    private JTextField cols;
    // button to create a new board
    private JButton createBoard;
    // button to cancel new board and return to
    // previous game
    private JButton cancel;
    // labels for rows per region
    private JLabel rowLabel;
    // label for columns per region
    private JLabel colLabel;
    // label dislayed when error occurs
    private JLabel errorMes;

    // JPanel object to house error message
    private JPanel center;
    // JPanel object to house rows and columns prompt
    private JPanel north;
    // JPanel object to house create new board and cancel buttons
    private JPanel south;
    // JDialog object to create window for new game
    private JDialog createWin2;

    /**
     * Constructs Dialog1 object.
     * 
     * @param win The window containing the dialog box.
     * @param header The title of the 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 New 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());
      south = 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);

      // keep track of "old" board
      final SudokuBase oldBoard = board;

      // add action listener for "Cancel" button
      cancel.addActionListener(new ActionListener() {

        /**
         * This method handles the action of activating the
         * "Cancel" button to make the dialog box "invisible".
         * 
         * @param e Captures information about the event that occurred.
         */
        public void actionPerformed(ActionEvent e) {
          setVisible(false);
        }
      });

      // add action listener for "Create Board" button
      createBoard.addActionListener(new ActionListener() {

        /**
         * This method handles the action of activating the
         * "Cancel" button to make the dialog box "invisible".
         * 
         * @param e Captures information about the event that occurred.
         */
        public void actionPerformed(ActionEvent e) {
          int newRows;
          int newCols;
          int newSize;

          // handles potential exception when converting String input
          // to int
          try{
            newRows = Integer.parseInt(rows.getText());
            newCols = Integer.parseInt(cols.getText());
          } catch (NumberFormatException nfe) {
            newRows = 0;
            newCols = 0;
          }

          newSize = newRows * newCols;
          // input validation
          if(newSize <= 0 || newSize > 12) {
            errorMes.setText("Rows times columns cannot be less than one" +
                             " or greater than 12!");
            errorMes.setVisible(true);
            pack();

          } else {
            errorMes.setVisible(false);
            setVisible(false);

            // update board to new board
            board = new SudokuBoard(newRows, newCols);
            createWin2 = new Dialog2(win, oldBoard, view, symbols, newRows,
                                     newCols, "New Sudoku Game", 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);
      // place both buttons at bottom
      south.add(createBoard);
      south.add(cancel);

      add(center, BorderLayout.CENTER);
      add(north, BorderLayout.NORTH);
      add(south, BorderLayout.SOUTH);

      pack();

      if(!win.win.isVisible()) {
        dispose();
      }

    }
  }

  // this inner class a dialog box to house a new game
  class Dialog2 extends JDialog {

    // view to be used
    private SudokuView view;

    // the panel to house the board (view) and both the
    // "Set givens" and "Cancel" buttons
    private JPanel panel;
    // panel placed within "panel" that houses both the "Set givens"
    // and "Cancel" buttons
    private JPanel northPanel;
    // panel to house the graphic "buttons"
    private JPanel symbols;

    // "Set givens" button
    private JButton setGivenCells;
    // "Cancel" button
    private JButton cancel;

    /**
     * Constructs Dialog2 object.
     * 
     * @param win The window containing the dialog box.
     * @param oldBoard The "old" SudokuBoard to keep track of.
     * @param oldView The "old" SudokuView to keep track of.
     * @param oldSymbols The "old" graphic "buttons" to keep track of.
     * @param rows The rows of the new Sudoku board to be created.
     * @param cols The columns of the new Sudoku board to be created.
     * @param header The title of the dialog box.
     * @param modal Whether the dialog box is modal or not.
     */
    public Dialog2(final SudokuMain mainWin, final SudokuBase oldBoard,
                   final SudokuView oldView, final JPanel oldSymbols,
                   int rows, int cols, String header, boolean modal) {
      // call superclass constructor
      super();

      // instantiate and bind to references
      view = new SudokuView(board);
      panel = new JPanel();
      northPanel = new JPanel();
      setGivenCells = new JButton("Set givens");
      cancel = new JButton("Cancel");
      symbols = new SetSymbols(view);

      // create menu bar
      final MenuAtTop menuBar = new MenuAtTop(mainWin);
      setJMenuBar(menuBar);

      // display "Set-Up Mode"
      final JLabel setupMode = new JLabel("Set-Up Mode");
      setupMode.setHorizontalAlignment(JLabel.CENTER);
      Font setupModeFont = new Font("Comic Sans MS", Font.BOLD, 18);
      setupMode.setFont(setupModeFont);
      setupMode.setForeground(Color.RED);

      // display "Normal Play Mode"
      final JLabel mode = new JLabel("Normal Play Mode");
      mode.setHorizontalAlignment(JLabel.CENTER);
      Font modeFont = new Font("Arial", Font.BOLD, 14);
      mode.setFont(modeFont);

      // set up characteristics
      setTitle(header);
      setModal(modal);
      setLayout(new FlowLayout());
      panel.setLayout(new BorderLayout());
      northPanel.setLayout(new FlowLayout());

      // add action listener to "Set givens" button
      setGivenCells.addActionListener(new ActionListener() {

        /**
         * This method handles the action of activating the
         * "Set givens" button.
         * 
         * @param e Captures information about the event that occurred.
         */
        public void actionPerformed(ActionEvent e) {
          // set "given" cells
          board.fixGivens();

//          // have window refer to new board
//          mainWin.west.remove(mainWin.symbols);
//          mainWin.east.remove(mainWin.view);
//          
//          mainWin.view = view;
//          mainWin.symbols = symbols;
//          
//          mainWin.west.add(mainWin.symbols);
//          mainWin.east.add(mainWin.view);

          // remove "Set-Up Mode" label and replace with
          // "Normal Play Mode" label
          panel.remove(setupMode);
          panel.add(mode, BorderLayout.SOUTH);

          // disable both buttons
          setGivenCells.setEnabled(false);
          cancel.setEnabled(false);

          validate();
          repaint();

        }
      });

      // add action listener to "Cancel" button
      cancel.addActionListener(new ActionListener() {

        /**
         * This method handles the action of activating the
         * "Cancel" button.
         * 
         * @param e Captures information about the event that occurred.
         */
        public void actionPerformed(ActionEvent e) {
          // have window refer to "old" board
          board = oldBoard;

          mainWin.west.remove(mainWin.symbols);
          mainWin.east.remove(mainWin.view);

          mainWin.view = oldView;
          mainWin.symbols = oldSymbols;

          mainWin.west.add(mainWin.symbols);
          mainWin.east.add(mainWin.view);

          // disable both buttons
          setGivenCells.setEnabled(false);
          cancel.setEnabled(false);

          setVisible(false);

          repaint();

        }
      });

      // place buttons at the top
      northPanel.add(setGivenCells);
      northPanel.add(cancel);

      // place board to fill remainder of space not
      // occupied by buttons at the top
      panel.add(view, BorderLayout.CENTER);
      panel.add(northPanel, BorderLayout.NORTH);
      panel.add(setupMode, BorderLayout.SOUTH);

      // place graphic "buttons" to left of board
      add(symbols);
      add(panel);

      setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      pack();
      setVisible(true);

    }

  }



// this inner class creates the graphic "buttons" to set the selected cell
  // to the desired "button"
  class SetSymbols extends JPanel {

    // temporary board provides information to create graphic "buttons"
    private SudokuBoard tempBd;

    private int value;

    /**
     * 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 colSymbol = 0; colSymbol < tempBd.getBoardSize(); colSymbol++) {
        // keep track of value of graphic "button"
        value = colSymbol;

        final JPanel symPanel = new JPanel();

        // set value for each graphic "button"
        tempBd.setValue(0, colSymbol, colSymbol);
        // add the appropriate symbol to each graphic "button"
        symPanel.add(new SudokuControlButton(view, value));

        // add graphic "button"
        add(symPanel);

      }

    }

    /**
     * Draws the symbol associated with each
     * numeric value (0 to 12) on the non-given
     * selected cell.
     * 
     * @param g The drawing mechanism.
     */
    public void paintComponent(Graphics g) {
      super.paintComponent(g);

      // get selected cell information from SudokuView reference
      int row = view.getSelectedRow();
      int col = view.getSelectedColumn();

      switch(value) {
        case 0:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 1:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 2:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 3:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 4:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 5:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 6:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 7:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 8:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 9:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 10:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 11:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
        case 12:
          view.new SudokuCell(row, col, board).drawSymbol(g, row, col);
          break;
      }

    }

  }

  // this inner class displays the state information for each row, column, and region
  class ShowStates extends JPanel{

    // the SudokuView object to be used
    private SudokuView view;

    // JPanel for row state
    private JPanel rowSt;
    // JPanel for column state
    private JPanel columnSt;
    // JPanel for region state
    private JPanel regionSt;
    // displays row state
    private JPanel[] rowStColor;
    // displays column state
    private JPanel[] columnStColor;
    // displays region state
    private JPanel[] regionStColor;

    // number of rows per region
    private int rows;
    // number of columns per region
    private int columns;
    // size per region (rows * columns)
    private int size;

    /**
     * Constructs the ShowStates object.
     *
     * @param view The SudokuView object for ShowStates. 
     */
    public ShowStates(SudokuView v) {

      // bind to references
      rows = board.getRowsPerRegion();
      columns = board.getColumnsPerRegion();
      size = rows * columns;

      // bind to reference
      view = v;

      // row characteristics
      rowSt = new JPanel();
      rowSt.setLayout(new GridLayout(size, 1));
      rowStColor = new JPanel[size];
      rowSt.setPreferredSize(new Dimension(50, 50));
      rowSt.setBorder(BorderFactory.createLineBorder(Color.BLACK));

      // column characteristics
      columnSt = new JPanel();
      columnSt.setLayout(new GridLayout(1, size));
      columnStColor = new JPanel[size];
      columnSt.setPreferredSize(new Dimension(50, 50));
      columnSt.setBorder(BorderFactory.createLineBorder(Color.BLACK));

      // region characteristics
      regionSt = new JPanel();
      regionSt.setLayout(new GridLayout(rows, columns));
      regionStColor = new JPanel[size];
      regionSt.setPreferredSize(new Dimension(50, 50));
      regionSt.setBorder(BorderFactory.createLineBorder(Color.BLACK));

      for(int i = 0; i < size; i++) {
        // instantiate and bind to references
        JPanel rowPanel = new JPanel();
        JPanel columnPanel = new JPanel();
        JPanel regionPanel = new JPanel();

        rowStColor[i] = rowPanel;
        columnStColor[i] = columnPanel;
        regionStColor[i] = regionPanel;

        // add to respective JPanel objects
        rowSt.add(rowPanel);
        columnSt.add(columnPanel);
        regionSt.add(regionPanel);
      }

      // add each state to "this" JPanel
      add(rowSt);
      add(columnSt);
      add(regionSt);

    }

    /**
     * This method draws the appropriate color to display the state information.
     * 
     * @param g The drawing mechanism.
     */
    public void paintComponent(java.awt.Graphics g) {
      super.paintComponent(g);

      for(int i = 0; i < rows * columns; i++) {

        // check the state of each row
        if(board.getRowState(i) == SudokuBase.State.ERROR){
          rowStColor[i].setBackground(Color.RED);
        }
        else if(board.getRowState(i) == SudokuBase.State.INCOMPLETE) {
          rowStColor[i].setBackground(Color.YELLOW);
        }
        else { // board.getRowState(i) == SudokuBase.State.COMPLETE
          rowStColor[i].setBackground(Color.GREEN);
        }

        // check the state of each column
        if(board.getColumnState(i) == SudokuBase.State.ERROR){
          columnStColor[i].setBackground(Color.RED);
        }
        else if(board.getColumnState(i) == SudokuBase.State.INCOMPLETE) {
          columnStColor[i].setBackground(Color.YELLOW);
        }
        else { // board.getColumnState(i) == SudokuBase.State.COMPLETE
          columnStColor[i].setBackground(Color.GREEN);
        }

        // check the state of each region
        if(board.getRegionState(i) == SudokuBase.State.ERROR){
          regionStColor[i].setBackground(Color.RED);
        }
        else if(board.getRegionState(i) == SudokuBase.State.INCOMPLETE) {
          regionStColor[i].setBackground(Color.YELLOW);
        }
        else { // board.getRegionState(i) == SudokuBase.State.COMPLETE
          regionStColor[i].setBackground(Color.GREEN);
        }

      }

    }

  }

  /**
   * This method provides a pre-set board to start with in
   * "Normal Play" mode.
   * 
   * @return The board with the "givens" already set.
   */
  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;
  }

}
于 2013-07-26T03:47:01.427 回答