1

thank you for taking your time in reading this. I hope it is not confusing, and if any other information is needed, please let me know!

Issue: I am making a Snake like game and I've created a JFrame, and then added the JPanel. Well, if I do not set the size of it in the JFrame it will size to about 100 x 20. When I set the size of it, it stays at the dimensions set. However, if I pack() it, it will shrink back to the 100 x 20 or so, when I have defined the size in the JPanel. I've set the bounds as well, with no luck. I have use FlowLayout(), and BorderLayout() with no success either. Now my game runs correctly and have no issues with it, except for the frame. It will cut off the sides, unless i do some gymnastics, which I do not wish to do.

Objective: I would like to be able to have the Frame size correctly to my width and height specified, and have the panel moved down a bit to add space for text for the game so it is not blocking anything.

Basically I'm confused and flustered that I have spent a few days on this, and I have not been successful with anything so far.

JFrame Class:

public class main extends JFrame {

 /**
  * @param args the command line arguments
  */

 public main(){
     Board game = new Board();

     setLayout(new BorderLayout(0, 50));
     setSize(game.getGameWidth(), game.getGameHeight());
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
     setLocationRelativeTo(null);
     setTitle("BlockRunner");
     getContentPane().add(game);

     setResizable(false);
     setVisible(true);
 }
}

My Board class:

public class Board extends JPanel implements ActionListener, KeyListener{
 private int width = 600;
 private int height = 400;
 Board(){
     addKeyListener(this);
     setFocusable(true);
     setBackground(Color.LIGHT_GRAY);
     setSize(width, height);
     InitGame();
 }
}

I am willing to try anything someone is willing to put out there for me. Thank you for your time!

EDIT 1: (Due to a user's answer.) using setPerferredSize(), setMinmumSize() and setMaximumSize() does not affect the outcome of this.

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Twister1002
  • 559
  • 1
  • 9
  • 26

4 Answers4

5

You need to use a combination of getPreferred/Minimum/MaximumSize and a layout that will actually respect it.

Here, I've used a GridBagLayout set up so that the board will always stay the same size, but the cell will use the maximum amount of same.

If you want to keep the text at the bottom of the board (instead of the frame), remove the weighty constraint (and possibly the weightx) as well

enter image description hereenter image description here

public class TestBoardGame {

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

    public TestBoardGame() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new GridBagLayout());

                GridBagConstraints gbc = new GridBagConstraints();
                gbc.gridx = 0;
                gbc.gridy = 0;
                gbc.weightx = 1;
                gbc.weighty = 1;
                frame.add(new BoardGamePane(), gbc);

                gbc.gridx = 0;
                gbc.gridy = 1;
                gbc.weightx = 1;
                gbc.fill= GridBagConstraints.HORIZONTAL;
                JLabel text = new JLabel("Area for text");
                text.setHorizontalAlignment(JLabel.CENTER);
                frame.add(text, gbc);

                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class BoardGamePane extends JPanel {

        public BoardGamePane() {

            setBorder(new LineBorder(Color.RED));
            setBackground(Color.ORANGE);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 300);
        }

        @Override
        public Dimension getMinimumSize() {
            return getPreferredSize();
        }

        @Override
        public Dimension getMaximumSize() {
            return getPreferredSize();
        }

    }    
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Your code is better then your text ... overriding `getPreferredSize` if you do custom painting is far better then calling `setPreferredSize` – Robin Nov 15 '12 at 07:30
  • @MadProgrammer Thanks for posting this up! Very helpful for understanding what trashgod mentioned – WilliamShatner Nov 15 '12 at 16:07
  • Thank you for the solution. Although after some intense thinking, I realized my program isn't designed to be able to write data in the JFrame (Just go with me). I was hoping to move some g.drawString() into -15 to push up the text. It would have been easier. However I started thinking about it and realized how stupid I was. Applications can't do that! xD. But you're method worked for me. Thank you! – Twister1002 Nov 15 '12 at 16:18
4

Assuming that Board is used principally for drawing, you can override getPreferredSize() to return a suitable Dimension. When you pack() the enclosing Window, it will adopt the chosen size. See this Q&A for more, and avoid this pitfall.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • See also `center` in this related [answer](http://stackoverflow.com/a/12024012/230513). – trashgod Nov 14 '12 at 21:10
  • The Board was used to basically control the game. Thank you so much for your help though! It has helped and give me more insight on writing Java GUI's. – Twister1002 Nov 15 '12 at 22:53
0

I know you say that using setPreferredSize() isn't affecting the outcome, but two others and myself seem to think it is what should fix it. Can you try the following:

In main change this:

setSize(game.getGameWidth(), game.getGameHeight());

To:

setPreferredSize(new Dimension(game.getGameWidth(), game.getGameHeight()));

Then add pack() and see if the outcome has changed. Theoretically this should fix the issue unless something else is going on that we can't see.

WilliamShatner
  • 926
  • 2
  • 12
  • 25
  • [Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing](http://stackoverflow.com/q/7229226/230513)? – trashgod Nov 14 '12 at 20:49
  • @trashgod Thanks for the link :) it really helped that MadProgrammer's example showed exactly what you mentioned as well. I had been told a few times to avoid `setPreferredSize` and wondered why. – WilliamShatner Nov 15 '12 at 16:05
  • Yes, that [example](http://stackoverflow.com/a/13387411/230513) illustrates the flexibility and reliability afforded by overriding `getXxxSize()`. Your point about `pack()` is well taken; please, ping me if you update this answer. – trashgod Nov 15 '12 at 18:00
0

My preferred way of using swing is to have inner components set their preferred size, and have the JFrame pack.

So in total you need to:

  • remove setSize in JFrame (or change to setPreferredSize)
  • change setSize in JPanel to setPreferredSize.
  • call pack in JFrame after everything is done.

See if the code below does what you want.

public class Main extends JFrame {

    public Main() {
        Board game = new Board();

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        {
            Container contentPane = getContentPane();
            contentPane.setLayout(new BorderLayout(0, 50));
            JLabel label = new JLabel("hello world!");
            contentPane.add(label, BorderLayout.NORTH);
            contentPane.add(game, BorderLayout.CENTER);
        }
        pack();

        setResizable(false);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Main();
            }
        });
    }
}

and

public class Board extends JPanel {
    private int width = 600;
    private int height = 400;

    Board() {
        setFocusable(true);
        setBackground(Color.LIGHT_GRAY);
        setPreferredSize(new Dimension(width, height));
    }

}
Apiwat Chantawibul
  • 1,271
  • 1
  • 10
  • 20
  • [Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing](http://stackoverflow.com/q/7229226/230513)? – trashgod Nov 14 '12 at 21:05
  • Thank you for the link, but those are quite his personal feeling isn't it. The preferred sizes exist as just a "guide lines" for the layout manager. There was one time that I implemented my own layout manager, I could choose to ignore the preferred size or use it. There really is nothing wrong with them. – Apiwat Chantawibul Nov 14 '12 at 21:18
  • Not so much kleopatra's personal feelings as long experience implementing component libraries, as well as seeing `setXxxSize()` misused. Sadly, Twister1002 asks us to guess at why `Board` fails to respond reasonably to `pack()`. – trashgod Nov 14 '12 at 22:02
  • @trashgod I'm not asking for a guess. I've tried all of those combinations as it provided me no help, or difference. I do appreciate the link! – Twister1002 Nov 15 '12 at 06:12
  • @Twister1002: Your `Board` contains no components, so MadP's `BoardGamePane` is a reasonable approach. – trashgod Nov 15 '12 at 17:26
  • @trashgod I'm still learning on writing the whole GUI thing, so I understand. – Twister1002 Nov 15 '12 at 22:48