0

数独ゲームを作成しており、ゲームを保存、名前を付けて保存、および開くオプションを提供しようとしています。これを行うために JFileChooser を使用しています。保存 (または「名前を付けて保存」) はできますが、保存したファイルを開こうとするとエラーが発生します。私はプログラミングが初めてで、誰かが問題を見つけて、保存するときに数独ボードの内容を読み込む方法を教えてくれることを願っています (また、開いたときに数独ボードを再作成する方法も教えてください)ファイル)。Reader/Writer の代わりに InputStream/OutputStream を使用してこれを処理する簡単な方法があると聞きました...

これを実装する内部クラスのコードを次に示します (このテキスト ボックスの文字制限を超えずにクラス全体を投稿する方法があるかどうかはわかりません)。

  // 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 クラスの 2 番目と最後の部分

  // 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 に答える