I am making a GUI component to represent something like a Chess board in a window. Normally it will be a grid of 8x8 squares, although some variants require a 10x8 board etc. The first step is to make a panel that contains a grid of 8x8 components.
The class Board
extends JPanel
and uses a GridLayout
to model a grid of 8x8 components. In an effort to get something done these are simply of class Square
which extends JButton
. The trouble is that they're not squares!
The Board
has been added to a freshly instantiated JFrame
, packed and rendered on the screen. Of course, right now the board takes up the entire frame as it is resized by the user. The grid scales with the board and this distorts the squares into rectangles.
This is not entirely undesired behaviour. I would like the board to scale with the frame. However, I would like to ensure that the squares remain square at all times. The board could be rectangular (10x8) but should maintain a fixed proportion.
How do I get square squares?
You can choose to use a
LayoutManager
that honors the preferred size of the cells instead.GridLayout
will provide a equal amount of the available space to each cell, which doesn't appear to be quite what you want.For example, something like
GridBagLayout
Updated with proportional example
Now, if you want to do a proportional layout (so that each cell of the grid remains proportional to the other regardless of the available space), things begin to get ... fun ...
This got a bit long, so here is the quick answer: You can't maintain a square board with square squares given your board dimensions (8x8, 10x8) and fully fill the screen if the user can resize it. You should limit the size of the board so that it maintains the aspect ratio even if that means you have some blank space in your frame. OK, read on for the long-winded explanation...
There are two ways you can make this work. Either you can limit the possible sizes of the
JFrame
, or you can limit the size of yourBoard
so it doesn't always fill the frame. Limiting the size of the board is the more common method, so let's start with that.Option 1: Limiting the Board
If you are working with a fixed set of board dimensions (8x8, 10x8, and a couple others maybe), and assuming each square has some minimum size (1 pixel squares on a chess board don't sound too practical), there are only so many frame dimensions that the board can fully fill. If your frame is 80pixels by 80pixels, your 8x8 board fits perfectly. But as soon as the user resizes to something like 85x80 you're stuck because you can't fully fill that while maintaining squares with the board dimensions you gave.
In this case you want to leave 5 pixels empty, whether it's 5 above or below, or 2.5 above and below, or whatever, doesn't matter. This should sound familiar - it's an aspect ratio problem and basically why you can get black bars on the edges of your TV depending on TV vs. movie dimensions.
Option 2: Limiting the Frame
If you want the board to always fully fill the frame, probably not what you want, then you have to adjust the size of the frame after a user resizes it. Say you are using a 10x8 board, and the user sets the frame to 107x75. That's not too bad, and with a little math you can figure out 100x80 is your closest aspect ratio that works, and fix the window. It will probably a bit frustrating for the user if the window keeps jumping around on them though, especially if they tried to make it something way off like 50x200.
Last thoughts / Example
Limiting the board is most likely the correct solution. Everything from games to desktop apps follows that principle. Take the ribbon in MS Office products for example. As you make the window larger, the ribbon will expand (maintaining its proportions) until it hits it max size, and then you just get more space for your document. When you make the window smaller the ribbon gets smaller (again maintaining its proportions) until it hits a minimum size and then you start losing parts of it (remember, don't want 1x1 squares on your board).
On the other hand you can prevent the user from resizing the window at all. I'm pretty sure this is how MineSweeper works (don't have it on this computer to double check), and may be a better/easier solution for what you need.