简体   繁体   中英

how to remove or make invisible parent window using JDialog class

I am creating the Sudoku game and I was wondering if there was a way I could remove (or make invisible) the parent window when I create JDialog objects when the user requests a new Sudoku board. When I create a new board using a JDialog object (via my inner classes Dialog1 and Dialog2) all the JDialog objects are stacked on top of each other. Specifically, in the Dialog2 class, I want the underlying window that contains the previous game to disappear when the "Set givens" button is pressed.

I will post the separate classes if you want to visually observe the problem I am describing, but really only the first class should be relevant to the issue (SudokuMain).


Edit

Never mind, apparently there is a limit to the characters I can enter here. Well, here is SudokuMain with irrelevant sections of code removed:

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

      }

    }

  }

}

I suggest that you use a different tact. Rather than create a new JDialog for a new game, why not simply use the same view to show the new game. Either reset the current Sudoku board (probably the most common way to do this for a Sudoku game) or create a new JPanel view with a completely new Sudoku game and swap views with a CardLayout.


Edit
You state in comment:

I am interested in the reset technique you talked about. How would I go about doing that?

It all depends on how your code is written. Assuming that you are using an MVC type of program structure, you would likely give your model class a reset method, say called reset() or resetBoard() , and inside this method reset the logical part of your Sudoku grid to a new initial state. The model would then notify the view (the GUI portion of your code) of its changes (sometimes this is done through the mediation of the control class) and then it changes its view representation of the board to the model's new state.


Edit 2

Yeah, I am utilizing the MVC concept. Could I include the reset method in SudokuMain (the class that runs the program and contains the controller)?

I'm not clear on your program set up. Usually my MVC is structured like so:

  • Model: the "business logic" that underlies the application.
  • View: The GUI that displays the visual representation of the model and that interacts with the user.
  • Control: The go-between between model and view. User initiated events trigger the control to notify the model and possibly change the model's state.
  • Main: A very short program that does nothing more than create the above entities, ties them together, and sets the program running.

So there is no place in the structure above for the Main class to have reset functionality. The Model should have a method that when called resets its state, the Control should call this method in response to a user interacting (probably pushing a button) on the View.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM