【问题标题】:Sudoku game, serialization issue数独游戏,连载问题
【发布时间】:2013-07-25 04:08:36
【问题描述】:

我正在创建数独游戏,并尝试提供保存、另存为和打开游戏的选项。我正在使用 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();
    }

  }

【问题讨论】:

  • 你得到的错误是什么?
  • “我收到一个错误。” 您打算与我们分享这个错误,还是我们应该猜测?好的.. 对于TooManyKittensError,将隔壁的雄猫绝育。
  • 包含要保存信息的对象是SudokuMain2类的实例?向我们展示课程...
  • 我得到“打开文件时出错。”,然后在另一个对话框中我得到:“文件类型不正确。” SudokuMain2 类很长,当我尝试包含在最初的问题中时,它说我超出了文本框的字符限制。有什么我没有做的吗?

标签: java serialization


【解决方案1】:

这是 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();
      }
    }

  }

...

【讨论】:

    【解决方案2】:

    ... // 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;
      }
    
    }
    

    【讨论】:

    • 这里是分两期的 SudokuMain 课程。我知道它们不是答案,但我不知道如何发布我的大型课程。
    猜你喜欢
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 2021-01-31
    • 1970-01-01
    • 2021-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多