0

我正在创建数独游戏,我想知道当我在用户请求新的数独板时创建 JDialog 对象时,是否有一种方法可以删除(或使不可见)父窗口。当我使用 JDialog 对象(通过我的内部类 Dialog1 和 Dialog2)创建新板时,所有 JDialog 对象都堆叠在一起。具体来说,在 Dialog2 类中,我希望包含上一个游戏的基础窗口在按下“设置给定”按钮时消失。

如果您想直观地观察我所描述的问题,我将发布单独的类,但实际上只有第一类应该与问题相关(SudokuMain)。


编辑

没关系,显然我可以在这里输入的字符是有限的。好吧,这里是 SudokuMain,删除了不相关的代码部分:

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

public class SudokuMain extends JComponent {

  /**
   * 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;
  // JPanel object to hold graphic "buttons"
  private JPanel symbols;

  // 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();

    // graphic "buttons" for current Sudoku board
    symbols = new SetSymbols(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);

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

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

    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 in the "File" menu
    private JMenuItem newGame;

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

      // 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);

      // add action listener to "newGame" option
      newGame.addActionListener(this);

    }

    /**
     * This method handles the action of activating the "New Game"
     * option.
     * 
     * @param e Captures information about the event that occurred.
     */
    public void actionPerformed(ActionEvent e) {
      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);
    }

  }

  // 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 exc) {
            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();

          // 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);

      }

    }

  }

}
4

1 回答 1

2

我建议你使用不同的技巧。与其为新游戏创建新的 JDialog,不如简单地使用相同的视图来显示新游戏。要么重置当前的数独板(这可能是数独游戏最常用的方法),要么使用全新的数独游戏创建新的 JPanel 视图,并使用 CardLayout 交换视图。


编辑
您在评论中声明:

我对你所说的重置技术很感兴趣。我该怎么做呢?

这完全取决于您的代码是如何编写的。假设您使用的是 MVC 类型的程序结构,您可能会为模型类提供一个重置方法,例如称为reset()or resetBoard(),并在此方法中将数独网格的逻辑部分重置为新的初始状态。然后,模型将通知视图(代码的 GUI 部分)其更改(有时这是通过控制类的中介完成的),然后将其对板的视图表示更改为模型的新状态。


编辑 2

是的,我正在使用 MVC 概念。我可以在 SudokuMain(运行程序并包含控制器的类)中包含 reset 方法吗?

我不清楚你的程序设置。通常我的 MVC 的结构是这样的:

  • 模型:应用程序基础的“业务逻辑”。
  • 视图:显示模型的可视化表示并与用户交互的 GUI。
  • 控制:模型和视图之间的中间人。用户发起的事件触发控件通知模型并可能改变模型的状态。
  • Main:一个非常短的程序,它只是创建上述实体,将它们联系在一起,然后设置程序运行。

因此,在上面的结构中,Main 类没有任何位置具有重置功能。模型应该有一个方法,当被调用时重置它的状态,控件应该调用这个方法来响应用户在视图上的交互(可能是按下一个按钮)。

于 2013-07-23T21:38:17.377 回答