The key basically lies, in the fact, that the component doesn't knows it's actual size, till frame.pack()
won't be called. Hence after this I am performing this calculation, to determine how much empty space to put for Border
and again calling frame.pack()
to repack()
everything after putting the Border
.
Please do have a look at this example, and see if this suite your needs :
import java.awt.*;
import javax.swing.*;
public class MainMenu {
private JButton playButton;
private JButton instructionButton;
private JButton scoreboardButton;
private JButton exitButton;
private JPanel menuPanel;
private GridBagConstraints gbc;
public MainMenu() {
gbc = new GridBagConstraints();
gbc.insets = new Insets(15, 15, 15, 15);
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
}
private void displayGUI() {
JFrame frame = new JFrame("Main Menu");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel(new BorderLayout());
menuPanel = new JPanel(new GridBagLayout());
menuPanel.setOpaque(true);
menuPanel.setBackground(Color.BLACK);
playButton = new JButton("Play");
instructionButton = new JButton("Instructions");
scoreboardButton = new JButton("Scoreboard");
exitButton = new JButton("Exit");
addComp(menuPanel, playButton, 0, 0, 1, 1, 1.0, 0.20,
GridBagConstraints.HORIZONTAL);
addComp(menuPanel, instructionButton, 0, 1, 1, 1, 1.0, 0.20,
GridBagConstraints.HORIZONTAL);
addComp(menuPanel, scoreboardButton, 0, 2, 1, 1, 1.0, 0.20,
GridBagConstraints.HORIZONTAL);
addComp(menuPanel, exitButton, 0, 3, 1, 1, 1.0, 0.20,
GridBagConstraints.HORIZONTAL);
contentPane.add(menuPanel);
frame.setContentPane(contentPane);
frame.pack();
contentPane.setBorder(
BorderFactory.createEmptyBorder(
contentPane.getHeight() - (contentPane.getHeight() / 4),
20, 5, 20));
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void addComp(JPanel panel, JComponent comp,
int gridx, int gridy,
int gridwidth, int gridheight,
double weightx, double weighty,
int fill) {
gbc.gridx = gridx;
gbc.gridy = gridy;
gbc.gridwidth = gridwidth;
gbc.gridheight = gridheight;
gbc.weightx = weightx;
gbc.weighty = weighty;
gbc.fill = fill;
panel.add(comp, gbc);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
new MainMenu().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
Here is the output :

EDIT 1 :
Moreover, if you will use GridLayout
instead of using GridBagLayout
for the MainMenu
, then I guess the results will be more promising. Please have a look at this example for that change :
import java.awt.*;
import javax.swing.*;
public class MainMenu {
private JButton playButton;
private JButton instructionButton;
private JButton scoreboardButton;
private JButton exitButton;
private JPanel menuPanel;
private void displayGUI() {
JFrame frame = new JFrame("Main Menu");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel(new GridBagLayout());
menuPanel = new JPanel(new GridLayout(0, 1, 5, 5));
menuPanel.setBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5));
menuPanel.setOpaque(true);
menuPanel.setBackground(Color.BLACK);
playButton = new JButton("Play");
instructionButton = new JButton("Instructions");
scoreboardButton = new JButton("Scoreboard");
exitButton = new JButton("Exit");
menuPanel.add(playButton);
menuPanel.add(instructionButton);
menuPanel.add(scoreboardButton);
menuPanel.add(exitButton);
contentPane.add(menuPanel);
frame.setContentPane(contentPane);
frame.pack();
contentPane.setBorder(
BorderFactory.createEmptyBorder(
contentPane.getHeight() -
(contentPane.getHeight() -
(3 * menuPanel.getHeight())),
20, 0, 20));
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
new MainMenu().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
EDIT 2 :
Another variant is looking much better, though, this time, the base JPanel
is using GridLayout
and the MenuPanel
is using GridBagLayout
. Please have a look at this example :
import java.awt.*;
import javax.swing.*;
public class MainMenu {
private JButton playButton;
private JButton instructionButton;
private JButton scoreboardButton;
private JButton exitButton;
private JPanel menuPanel;
private GridBagConstraints gbc;
public MainMenu() {
gbc = new GridBagConstraints();
gbc.insets = new Insets(15, 15, 15, 15);
gbc.anchor = GridBagConstraints.CENTER;
}
private void displayGUI() {
JFrame frame = new JFrame("Main Menu");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel(new GridLayout(1, 1, 5, 2));
menuPanel = new JPanel(new GridBagLayout());
menuPanel.setBorder(
BorderFactory.createEmptyBorder(5, 5, 5, 5));
menuPanel.setOpaque(true);
menuPanel.setBackground(Color.BLACK);
playButton = new JButton("Play");
instructionButton = new JButton("Instructions");
scoreboardButton = new JButton("Scoreboard");
exitButton = new JButton("Exit");
addComp(menuPanel, playButton, 0, 0, 1, 1, 1.0, 0.10,
GridBagConstraints.CENTER);
addComp(menuPanel, instructionButton, 0, 1, 1, 1, 1.0, 0.10,
GridBagConstraints.CENTER);
addComp(menuPanel, scoreboardButton, 0, 2, 1, 1, 1.0, 0.10,
GridBagConstraints.CENTER);
addComp(menuPanel, exitButton, 0, 3, 1, 1, 1.0, 0.10,
GridBagConstraints.CENTER);
contentPane.add(menuPanel);
frame.setContentPane(contentPane);
frame.pack();
contentPane.setBorder(
BorderFactory.createEmptyBorder(
contentPane.getHeight() -
(contentPane.getHeight() -
(2 * menuPanel.getHeight()) + 100),
20, 2, 20));
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private void addComp(JPanel panel, JComponent comp,
int gridx, int gridy,
int gridwidth, int gridheight,
double weightx, double weighty,
int fill) {
gbc.gridx = gridx;
gbc.gridy = gridy;
gbc.gridwidth = gridwidth;
gbc.gridheight = gridheight;
gbc.weightx = weightx;
gbc.weighty = weighty;
gbc.fill = fill;
panel.add(comp, gbc);
}
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
new MainMenu().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}