6

I am implementing changes to a minesweeper game. One of these things is the difficulty. I have managed to do this and its working, but as the game board (in its own Jpanel) gets bigger & smaller (depending on the difficulty), I cannot get the JFrame to resize automatically. I am using:

setPreferredSize(new Dimension(WIDTH, HEIGHT));

to set the initial size of the window, but this makes it REALLY tiny, as in only showing the word 'File' from the JMenuBar. I have to resize it manually.

I tried setSize() and things like frame.pack() on the ActionListener event, but I cannot seem to get it to resize.

Any tips on what code/methods to use.

edit: code posted

package mines;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class SetupFrame extends JFrame {

    private final int WIDTH = 600;
    private final int HEIGHT = 500;
    public JFrame frame;
    public JMenuBar menubar;
    public JMenu file;
    public JMenu levels;
    public JMenu help;
    public JMenuItem login;
    public JMenuItem save;
    public JMenuItem resume;
    public JMenuItem exit;
    public JMenuItem easy;
    public JMenuItem medium;
    public JMenuItem hard;
    private JLabel statusbar;
    public JPanel main;
    public JPanel buttonPanel;
    public JPanel saved;
    public JPanel game;
    public Board mineGame;
    public JButton ngButton;
    public JButton undoButton;
    public JButton redoButton;
    public JTabbedPane tp;
    public String[] levelPicker;
    public JComboBox levelSelect;
    public JFileChooser chooser;
    public String filename;

    public int difficulty;

    public SetupFrame(){

      frame = new JFrame();

      String filename = JOptionPane.showInputDialog(frame, "Enter Your Name.");

      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);


      setLocationRelativeTo(null);
      setTitle("Minesweeper");

      //menubar, menus, menu items
      menubar = new JMenuBar();
      setJMenuBar(menubar);

      file = new JMenu("File");
      help = new JMenu("Help");

      menubar.add(file);
      menubar.add(help);

      login = new JMenuItem("Login..");
      save = new JMenuItem("Save..");
      resume = new JMenuItem("Resume..");
      exit = new JMenuItem("Exit");

      file.add(login);
      file.add(save);
      file.add(resume);
      file.addSeparator();
      file.add(exit);

      statusbar = new JLabel("");



      chooser = new JFileChooser(); // new File Chooser for saved tab
      undoButton = new JButton(" Undo "); //undo Button for game panel 
      ngButton = new JButton(" New Game ");//new game Button for game panel
      redoButton = new JButton(" Redo");//redo Button for game panel

      main = new JPanel(new BorderLayout()); //new panel for main game
      //main.add(mineGame, BorderLayout.CENTER); //add instance mineGame to main panel

      game = new JPanel(new BorderLayout());// new panel for game tab
      main.add(game, BorderLayout.CENTER); //add the mineGames panel to game panel
      game.add(statusbar, BorderLayout.SOUTH); //add statusbar to bottom of game panel
            //game.add(button, BorderLayout.NORTH); // add buttons (eventually be redo, undo, new game)

      saved = new JPanel(); // create new panel for the saved tab
      saved.add(chooser);//add the File Chooser to the saved tab

      String[] levelPicker = {"Easy", "Medium", "Hard"};
      levelSelect = new JComboBox(levelPicker);
      levelSelect.setSelectedIndex(0);
            //levelSelect.addActionListener(this);

       buttonPanel = new JPanel();
       buttonPanel.add(undoButton);
       buttonPanel.add(ngButton);
       buttonPanel.add(redoButton);
       buttonPanel.add(levelSelect);
       main.add(buttonPanel, BorderLayout.NORTH);

       //create & add the tabs
       tp = new JTabbedPane();
       tp.addTab ("Game", main);
       tp.addTab ("Saved", saved);
       tp.addTab ("Statistics", null);
       add(tp);

       setPreferredSize(new Dimension(WIDTH, HEIGHT));
       setResizable(true);
       setVisible(true);
       frame.pack();


        class listener implements ActionListener{
            public void actionPerformed (ActionEvent e)
            {   
                if(e.getSource() == ngButton){
                    //JOptionPane.showInputDialog(frame, "Do You want To Save");
                    newMineGame();
                }
                JComboBox cb = (JComboBox)e.getSource();
                String picker = (String)cb.getSelectedItem();
                if (picker == "Easy"){
                    difficulty = 0;
                    newMineGame();
                }
                if (picker == "Medium"){
                    difficulty = 1;
                    newMineGame();
                    frame.pack();
                }
                if (picker == "Hard"){
                    difficulty = 2;
                    newMineGame();
                    frame.pack();
                }
            }


            private void newMineGame() {
                game.removeAll();
                mineGame = new Board(statusbar, difficulty);
                game.add(mineGame, BorderLayout.CENTER);
                game.add(statusbar, BorderLayout.SOUTH);
                repaint();
            }

        }

        ngButton.addActionListener(new listener());
        undoButton.addActionListener(new listener());
        redoButton.addActionListener(new listener());
        levelSelect.addActionListener(new listener());


    }

public static void main(String[] args) {
        new SetupFrame();

    }
Ange King
  • 147
  • 1
  • 2
  • 12
  • 1
    You appear to be using the right methods, but probably incorrectly. Post your code. – Josh M Oct 04 '13 at 11:46
  • Additionally are you using the methods on the JPanel or the JFrame? – Levenal Oct 04 '13 at 11:48
  • Using `validate();` or `revalidate();` tends to 'refresh' the JFrame/JPanel - have you tried using those? – crazyloonybin Oct 04 '13 at 11:50
  • use CardLayout as easiest of possible ways – mKorbel Oct 04 '13 at 12:04
  • For better help sooner, post an [SSCCE](http://sscce.org/). See the [Nested Layout Example](http://stackoverflow.com/a/5630271/418556) for a working example of resizing on PLAF change. – Andrew Thompson Oct 04 '13 at 12:10
  • @mKorbel - where should I use card layout? for the different difficulty levels? or instead of JTabbedPane? – Ange King Oct 04 '13 at 12:20
  • @user2777005 I am assuming I am using them on the frame as I have frame.pack(); – Ange King Oct 04 '13 at 12:21
  • @Ange King add all three Boards types as the Cards to CardLayout – mKorbel Oct 04 '13 at 12:38
  • @AngeKing : Adding a call to `pack()` as the last line (instead of repaint()), inside the `newMineGame()` method, seems to do the trick as stated by __mKorbel__. You playing with wrong references, in the code. You creating them unnecessarily like instead of using `frame.pack()` use `this.pack()`, why to create this new object of `JFrame` when the class already extends `JFrame` ? – nIcE cOw Oct 04 '13 at 13:32
  • @nIcE cOw: Thanks for the info. I updated my code as per what mKorbel advised below, but it is still not working. It obviously has something to do with the Board class, it is a Jpanel, so not sure what to do. I really didn't want to play around with GridBagLayout as it seems really complicated to me (I'm a total newb, it you couldn't already tell). Will have to do further reading :-) – Ange King Oct 04 '13 at 13:58

2 Answers2

10

One of these things is the difficulty. I have managed to do this and its working, but as the game board (in its own Jpanel) gets bigger & smaller (depending on the difficulty), I cannot get the JFrame to resize automatically.

and

tried setSize() and things like frame.pack() on the ActionListener event, but I cannot seem to get it to resize.

  • JFrame.pack() works in case

    1. that all JComponents representing mines (there is best of ways to use JToggleButton) returns properly PreferredSize back to its parent (JPanel)

    2. parent (JPanel) laid by GridLayout (very simple)

    3. and there are two ways how, when, where to JFrame.pack()

      • use CardLayout, the next code line after swithching Card is JFrame.pack()

      • remove old JPanel (from JFrame) and replace with new, then you need to call JFrame.(re)validate(), JFrame.repaint() and JFrame.pack() as last code lines

  • maybe there is another issue, important is code ordering in the case that is there settings for JFrame.setResizable(false);


after your edit

  • use Cardlayout

  • there you miss code lines (don't to extends JFrame, create this Object as Local variable) JFrame.(re)validate(), JFrame.repaint() and JFrame.pack() as last code lines in private void newMineGame() {


but I dont understand what you mean by: "there you miss code lines (don't to extends JFrame, create this Object as Local variable) ;

code could be

import javax.swing.*;

public class SetupFrame {

    private JFrame frame;
    private JMenuBar menubar = new JMenuBar();
    private Board mineGame;

    public SetupFrame() {
        //there add required JComponents

        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setTitle("Minesweeper");
        frame.setJMenuBar(menubar);
        frame.add(mineGame);
        //frame.setPreferredSize(new Dimension(WIDTH, HEIGHT));
        //frame.setResizable(true);//not neccessary
        frame.pack();
        frame.setVisible(true);
    }

    private void newMineGame() {
        //remove old Board
        //add a new Board
        frame.validate();
        frame.repaint();
        frame.pack();
    }

    private static void main(String[] args) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new SetupFrame();
            }
        });
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • thanks for your answer, but I dont understand what you mean by: "there you miss code lines (don't to extends JFrame, create this Object as Local variable) ; – Ange King Oct 04 '13 at 12:14
  • remove `extends JFrame` from `public class SetupFrame extends JFrame {`, because there are two `JFrame`s, one of them is never visible, and to this `JFrame` are made changes, you would need to add `frame.` before every `setXxxXxx` and `add()`, in `IDE` there are red warnings – mKorbel Oct 04 '13 at 12:23
  • Thank you. I made the changes, but unfortunately, the JFrame is still not resizing :-(. – Ange King Oct 04 '13 at 12:51
  • everything came from Board, remove all settings for H & W, override set/getPreferredSize for 1st. element in grid, note must be laid by Grid(Bag)Layout, then there isn't required any setting for setSize, setPreferredSize for any of its parents, e.g. JPanel, JFrame etc. – mKorbel Oct 04 '13 at 12:58
7

Here is your mistake:

frame.pack();

Why do you need frame if your SetupFrame actually extends from JFrame? Change this line by just pack() and it will work.

@mKorbel already posted a complete and very useful explanation about pack() behavior (thank you).

Update

Also in your listener class you'll get this exception when a JButton is pressed:

java.lang.ClassCastException: javax.swing.JButton cannot be cast to javax.swing.JComboBox

You need make this little change to avoid this:

class listener implements ActionListener{

    public void actionPerformed (ActionEvent e) {
        if(e.getSource() == ngButton){
            //JOptionPane.showInputDialog(frame, "Do You want To Save");
            newMineGame();
        } else if(e.getSource() instanceof JComboBox){ // add this else-if block
            JComboBox cb = (JComboBox)e.getSource();
            String picker = (String)cb.getSelectedItem();
            if (picker.equals("Easy")){ // <-- picker == "Easy" is not the proper way to compare string, use equals() method instead
                difficulty = 0;
                newMineGame();
            }
            if (picker.equals("Medium")){
                difficulty = 1;
                newMineGame();
                //frame.pack();  <--- again, just use pack();
                pack();
            }
            if (picker.equals("Hard")){
                difficulty = 2;
                newMineGame();
                //frame.pack();  <--- again, just use pack();
                pack();
            }
        }
    }

Or even better, implement an ItemListener to listen JComboBox selection changes instead using an ActionListener

dic19
  • 17,821
  • 6
  • 40
  • 69
  • Thanks. I actually tried pack() but itself, it didn't work. As I said, I have tried numerous things and frame.pack(); was just the last thing I tried :-) – Ange King Oct 04 '13 at 12:17
  • @AngeKing Are you sure? I just did that change and it worked like a charm to me. I don't have `Board` class to test the behavior when the difficulty level changes. Please see updated answer, I found a little bug. – dic19 Oct 04 '13 at 12:36
  • Thank you for the tip. I changed the code, and I saw my error of adding another frame. it still doesn't resize on the change of difficulty level, so I will have a look into the ItemListener. – Ange King Oct 04 '13 at 12:40