I'm just learning about GridBagLayout. When I add a JTextField to my layout, everything seems to disappear
// final JTextField textField = new JTextField("textField");
// addComponentToGridbag(textField, 0,0,1,1);
JButton button = new JButton("Button");
addComponentToGridbag(button, 1,0,1,1);
If I leave those first two lines commented out, I get this, which is OK except that there is no text field (of course):
But I want a text field to appear directly above the button, so I uncomment those two lines. And then I get this (notice how not only did my button disappear, but so did my top and bottom panels):
What is going on? How can I get a text field to appear without losing the other stuff? Thanks!
Here is the entire class:
public class GUI {
private JFrame frame;
private JPanel topPanel = new JPanel();
private JPanel bottomPanel = new JPanel();
private GridBagLayout layout = new GridBagLayout();
private GridBagConstraints constraints = new GridBagConstraints();
private JPanel centerPanel = new JPanel();
public GUI() {
makeMainFrame();
makePanels();
bodyLayout();
JLabel title = new JLabel("Dashboard");
topPanel.add(title);
JButton btnExit = new JButton("Exit");
bottomPanel.add(btnExit);
}
private void bodyLayout() {
centerPanel.setLayout(layout);
final JTextField textField = new JTextField("textField");
addComponentToGridbag(textField, 0,0,1,1);
JButton btnFetchMetaData = new JButton("Button");
addComponentToGridbag(btnFetchMetaData, 1,0,1,1);
}
private void addComponentToGridbag(Component component, int row, int column, int width, int height) {
constraints.gridx = column;
constraints.gridy = row;
constraints.gridwidth = width;
constraints.gridheight = height;
layout.setConstraints(component, constraints);
centerPanel.add(component);
}
private void makeMainFrame() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int height = (int) (screenSize.height * 0.75);
int width = (int) (screenSize.width * 0.75);
frame = new JFrame();
frame.setVisible(true);
frame.setTitle("Learning Java Swing");
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.getContentPane().setLayout(new BorderLayout(0, 0));
}
private void makePanels() {
frame.getContentPane().add(topPanel, BorderLayout.NORTH);
frame.getContentPane().add(bottomPanel, BorderLayout.SOUTH);
centerPanel.setBackground(Color.RED);
centerPanel.setOpaque(true);
frame.getContentPane().add(centerPanel, BorderLayout.CENTER);
}
Reusing the same GridBagConstraints object might be a problem. Try always creating new GridBagConstraints in addComponentToGridbag method
Related
I am making a form by using FlowLayout. The GUI of the form is shown below:
Name: <textField>
Age: <textfiedl>
Gender: Male[] Female[]
Email: <textField>
For gender, the options are radio buttons. As you can see, the labels for age and gender should be centered. How can I do this using FlowLayout?
This is one way (of a plethora of ways it might be done). Layout details in titled borders.
Note: For anything to do with selecting a number, it's better to offer the user a spinner.
If the whole form is created using BoxLayout, one oriented as BoxLayout.PAGE_AXIS, then if each "line" of the form is a JPanel that uses FlowLayout, the components that they held should be centered by default, since JPanel uses new FlowLayout(FlowLayout.CENTER, 5, 5) as its default layout (actually it uses new FlowLayout(), but the default values for this constructor are as above -- CENTER orientation with horizontal and vertical gaps of 5).
Another option is to use a GridBagLayout, and alter the constraints' FILL and weighty properties for the component on each row.
For example:
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.*;
public class LayoutExample extends JPanel {
private static final long serialVersionUID = 1L;
private JTextField ageField = new JTextField(10);
private JTextField emailField = new JTextField(10);
private ButtonGroup sexBtnGroup = new ButtonGroup();
private JRadioButton maleBtn = new JRadioButton("Male");
private JRadioButton femaleBtn = new JRadioButton("Female");
public LayoutExample() {
JPanel agePanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
agePanel.add(new JLabel("Age:"));
agePanel.add(ageField);
sexBtnGroup.add(maleBtn);
sexBtnGroup.add(femaleBtn);;
JPanel sexSelectionPanel = new JPanel();
sexSelectionPanel.add(new JLabel("Select Sex:"));
sexSelectionPanel.add(maleBtn);
sexSelectionPanel.add(femaleBtn);
JPanel emailPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
emailPanel.add(new JLabel("Email:"));
emailPanel.add(emailField);
int gap = 10;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(agePanel);
add(Box.createVerticalStrut(5));
add(sexSelectionPanel);
add(Box.createVerticalStrut(5));
add(emailPanel);
}
// make it stretch horizontally to see placement
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
int width = (3 * superSize.width) / 2;
int height = superSize.height;
return new Dimension(width, height);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
LayoutExample mainPanel = new LayoutExample();
JFrame frame = new JFrame("LayoutExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
Example 2 using a GridBagLayout:
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import javax.swing.*;
public class LayoutExample2 extends JPanel {
private static final long serialVersionUID = 1L;
private JTextField ageField = new JTextField(10);
private JTextField emailField = new JTextField(10);
private ButtonGroup sexBtnGroup = new ButtonGroup();
private JRadioButton maleBtn = new JRadioButton("Male");
private JRadioButton femaleBtn = new JRadioButton("Female");
public LayoutExample2() {
JPanel sexSelectPanel = new JPanel(new GridLayout(1, 0, 5, 5));
sexBtnGroup.add(maleBtn);
sexSelectPanel.add(maleBtn);
sexBtnGroup.add(femaleBtn);
sexSelectPanel.add(femaleBtn);
int gap = 10;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
setLayout(new GridBagLayout());
add(new JLabel("Age:"), createGbc(0, 0));
add(ageField, createGbc(1, 0));
add(new JLabel("Sex:"), createGbc(0, 1));
add(sexSelectPanel, createGbc(1, 1));
add(new JLabel("Email:"), createGbc(0, 2));
add(emailField, createGbc(1, 2));
}
private static GridBagConstraints createGbc(int x, int y) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = x;
gbc.gridy = y;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
int ins = 4;
gbc.insets = new Insets(ins, ins, ins, ins);
gbc.fill = GridBagConstraints.HORIZONTAL;
return gbc;
}
// make it stretch horizontally to see placement
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
int width = (4 * superSize.width) / 3;
int height = superSize.height;
return new Dimension(width, height);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
LayoutExample2 mainPanel = new LayoutExample2();
JFrame frame = new JFrame("LayoutExample");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
I have the GUI displaying properly for the most part, except for one thing. The TitledBorder("Numeric Type") does not display the entire title for the right JPanel. I believe it has something to do with the BorderLayout Manager. Instead of displaying "Numeric Type" within the border, just "Numeric..." displays. Any help will be greatly appreciated.
public class P3GUI extends JFrame {
private JLabel originalList;
private JTextField originalSort;
private JLabel sortedList;
private JTextField newSort;
private JPanel panel;
private JButton performSort;
private JRadioButton ascending;
private JRadioButton descending;
private ButtonGroup sort;
private JRadioButton integer;
private JRadioButton fraction;
private ButtonGroup numType;
private JPanel inputPanel, outputPanel, calculatePanel, radioPanel;
private JPanel left, right;
public P3GUI () {
super("Binary Search Tree Sort");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
originalList = new JLabel("Original List");
originalSort = new JTextField(20);
inputPanel = new JPanel();
inputPanel.add(originalList);
inputPanel.add(originalSort);
sortedList = new JLabel("Sorted List");
newSort = new JTextField(20);
newSort.setEditable(false);
outputPanel = new JPanel();
outputPanel.add(sortedList);
outputPanel.add(newSort);
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(inputPanel);
panel.add(outputPanel);
add(panel, BorderLayout.NORTH);
performSort = new JButton("Perform Sort");
calculatePanel = new JPanel();
calculatePanel.add(performSort);
add(calculatePanel, BorderLayout.CENTER);
ascending = new JRadioButton("Ascending");
descending = new JRadioButton("Descending");
sort = new ButtonGroup();
sort.add(ascending);
sort.add(descending);
integer = new JRadioButton("Integer");
fraction = new JRadioButton("Fraction");
numType = new ButtonGroup();
numType.add(integer);
numType.add(fraction);
radioPanel = new JPanel();
radioPanel.setLayout(new FlowLayout());
left = new JPanel();
left.setLayout(new GridLayout(2,1));
left.setBorder(BorderFactory.createTitledBorder("Sort Order"));
left.add(ascending);
left.add(descending);
right = new JPanel();
right.setLayout(new GridLayout(2,1));
right.setBorder(BorderFactory.createTitledBorder("Numeric Type"));
right.add(integer);
right.add(fraction);
radioPanel.add(left);
radioPanel.add(right);
add(radioPanel, BorderLayout.SOUTH);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
new P3GUI().setVisible(true);
}
});
}
}
The problem is that the right JPanel is too small to display the entire title, and so it gets truncated. I'd suggest placing the bottom two JPanels into another that uses GridLayout, and then place them in such a way that they expand to fit the bottom of your GUI. When spread out, the title has a much greater chance of being fully displayed (but not a guarantee, mind you!).
For example, if you make the main GUI use a BorderLayout, and add this GridLayout using JPanel into the BorderLayout.CENTER position, it will fill it completely. Then the top components, the TextFields and JButton can be added to another JPanel, say one that uses a GridBagLayout, and add that to the main JPanel's BorderLayout.PAGE_START position.
For example, the following code produces this GUI:
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class P3GUI2 extends JPanel {
private static final int COLS = 20;
private JTextField originalSort = new JTextField(COLS);
private JTextField newSort = new JTextField(COLS);
private JButton performSort = new JButton("Perform Sort");
private JRadioButton ascending = new JRadioButton("Ascending");
private JRadioButton descending = new JRadioButton("Descending");
private ButtonGroup sort = new ButtonGroup();
private JRadioButton integer = new JRadioButton("Integer");
private JRadioButton fraction = new JRadioButton("Fraction");
private ButtonGroup numType = new ButtonGroup();
public P3GUI2() {
JPanel topPanel = new JPanel(new GridBagLayout());
topPanel.add(new JLabel("Original List:"), createGbc(0, 0));
topPanel.add(originalSort, createGbc(1, 0));
topPanel.add(new JLabel("Sorted List:"), createGbc(0, 1));
topPanel.add(newSort, createGbc(1, 1));
performSort.setMnemonic(KeyEvent.VK_P);
JPanel btnPanel = new JPanel();
btnPanel.add(performSort);
JPanel sortOrderPanel = createTitlePanel("Sort Order");
JPanel numericPanel = createTitlePanel("Numeric Type");
sortOrderPanel.add(ascending);
sortOrderPanel.add(descending);
sort.add(ascending);
sort.add(descending);
numericPanel.add(integer);
numericPanel.add(fraction);
numType.add(integer);
numType.add(fraction);
JPanel radioPanels = new JPanel(new GridLayout(1, 0, 3, 3));
radioPanels.add(sortOrderPanel);
radioPanels.add(numericPanel);
setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
setLayout(new BorderLayout(3, 3));
add(topPanel, BorderLayout.PAGE_START);
add(btnPanel, BorderLayout.CENTER);
add(radioPanels, BorderLayout.PAGE_END);
}
private JPanel createTitlePanel(String title) {
JPanel panel = new JPanel(new GridLayout(0, 1, 3, 3));
panel.setBorder(BorderFactory.createTitledBorder(title));
return panel;
}
private GridBagConstraints createGbc(int x, int y) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = x;
gbc.gridy = y;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = x == 0 ? GridBagConstraints.WEST : GridBagConstraints.EAST;
gbc.insets = new Insets(3, 3, 3, 3);
gbc.weightx = 1.0;
gbc.weighty = 1.0;
return gbc;
}
private static void createAndShowGui() {
P3GUI2 mainPanel = new P3GUI2();
JFrame frame = new JFrame("Binary Search Tree Sort");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
Or you could place the above btnPanel into the main one BorderLayout.CENTER and then place the radioPanels into the main one BorderLayout.PAGE_END. This will display a GUI of the same appearance but it will expand differently if re-sized.
The preferred size of the panel (as determined by the layout manager) does not consider the size of the text in the TitledBorder so the title can get truncated.
Here is a custom JPanel that can be used with a TitleBorder. The getPreferredSize() method has been customized to use the maximum width of:
the default getPreferredSize() calculation
the width of the text in the TitledBorder
Here is a simple example:
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class TitledBorderPanel extends JPanel
{
/**
** The preferred width on the panel must consider the width of the text
** used on the TitledBorder
*/
#Override
public Dimension getPreferredSize()
{
Dimension preferredSize = super.getPreferredSize();
Border border = getBorder();
int borderWidth = 0;
if (border instanceof TitledBorder)
{
Insets insets = getInsets();
TitledBorder titledBorder = (TitledBorder)border;
borderWidth = titledBorder.getMinimumSize(this).width + insets.left + insets.right;
}
int preferredWidth = Math.max(preferredSize.width, borderWidth);
return new Dimension(preferredWidth, preferredSize.height);
}
private static void createAndShowGUI()
{
JPanel panel = new TitledBorderPanel();
panel.setBorder( BorderFactory.createTitledBorder("File Options Command List:") );
panel.setLayout( new BoxLayout(panel, BoxLayout.Y_AXIS) );
panel.add( new JLabel("Open") );
panel.add( new JLabel("Close") );
// panel.add( new JLabel("A really wierd file option longer than border title") );
JFrame frame = new JFrame("TitledBorderPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( panel );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}
I'm trying to get the config panel to take up the top of the screen, and then have the input and output panels side-by-side. I'm also trying to get the text areas to be 70 characters wide each and 30 rows tall. However, right now, the config panel isn't showing up at all, and the text areas are only 35 characters wide and 2 rows tall. I've followed all the examples and tutorials I've found. What am I doing wrong?
public class BorderWrapper {
public static void main(String[] args) {
//Create frame
JFrame frame = new JFrame("Border Wrapper");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create main panel
MainPanel panel = new MainPanel();
frame.getContentPane().add(panel, BorderLayout.NORTH);
//Display frame
Dimension minSize = new Dimension(650, 375);
frame.setPreferredSize(minSize);
frame.setMinimumSize(minSize);
frame.pack();
frame.setVisible(true);
}
}
public class MainPanel extends JPanel {
private static final Font INPUT_FONT = new Font("Monospaced", Font.PLAIN, 12);
private JTextArea inputArea, outputArea;
private JTextField titleField, topBorderField, sideBorderField;
public MainPanel() {
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
//Set up config panel
JPanel configPanel = new JPanel();
configPanel.setLayout(new BoxLayout(configPanel, BoxLayout.X_AXIS));
configPanel.setMaximumSize(new Dimension(400, 200));
titleField = new JTextField(25);
titleField.setFont(INPUT_FONT);
topBorderField = new JTextField(1);
topBorderField.setFont(INPUT_FONT);
sideBorderField = new JTextField(4);
sideBorderField.setFont(INPUT_FONT);
configPanel.add(new JLabel("Title:"));
configPanel.add(titleField);
configPanel.add(new JLabel("Top border:"));
configPanel.add(topBorderField);
configPanel.add(new JLabel("Side border:"));
configPanel.add(sideBorderField);
c.gridwidth = 2;
c.gridx = 0;
c.gridy = 0;
add(configPanel, c);
//Set up Input panel
JPanel inputPanel = new JPanel();
inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS));
inputArea = new JTextArea("Type or paste your stuff here . . .");
inputArea.setFont(INPUT_FONT);
inputArea.setLineWrap(true);
inputArea.setWrapStyleWord(true);
inputArea.setColumns(75);
JScrollPane inputPane = new JScrollPane(inputArea);
inputPane.setMinimumSize(new Dimension(250, 400));
JLabel inputLabel = new JLabel("Text Box");
inputLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
inputPanel.add(inputLabel);
inputPanel.add(inputPane);
inputPanel.setMinimumSize(new Dimension(250, 400));
c.gridwidth = 1;
c.gridx = 0;
c.gridy = 1;
add(inputPanel, c);
//Set up Output panel
JPanel outputPanel = new JPanel();
outputPanel.setLayout(new BoxLayout(outputPanel, BoxLayout.Y_AXIS));
outputArea = new JTextArea();
outputArea.setFont(INPUT_FONT);
outputArea.setLineWrap(true);
outputArea.setWrapStyleWord(true);
outputArea.setColumns(75);
JScrollPane outputPane = new JScrollPane(outputArea);
outputPane.setMinimumSize(new Dimension(250, 400));
JLabel outputLabel = new JLabel("Wrapped Output");
outputLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
outputPanel.add(outputLabel);
outputPanel.add(outputPane);
outputPanel.setMinimumSize(new Dimension(250, 400));
c.gridwidth = 1;
c.gridx = 1;
c.gridy = 1;
add(outputPanel, c);
}
}
Originally, I was going to try to use a BorderLayout, since it seemed that made the most sense for the layout I was trying to make, but that did an even worse job when I set them to BorderLayout.WEST and BorderLayout.EAST.
Have modified your program to use BorderLayout in the MainPanel and few other minor changes to get the desired look and feel.Check if this helps.
public class BorderWrapper {
public static void main(String[] args) {
// Create frame
JFrame frame = new JFrame("Border Wrapper");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Create main panel
MainPanel panel = new MainPanel();
frame.getContentPane().add(panel);
// Display frame
Dimension minSize = new Dimension(650, 375);
frame.setPreferredSize(minSize);
frame.setMinimumSize(minSize);
frame.pack();
frame.setVisible(true);
}
}
class MainPanel extends JPanel {
private static final Font INPUT_FONT = new Font("Monospaced", Font.PLAIN, 12);
private JTextArea inputArea, outputArea;
private JTextField titleField, topBorderField, sideBorderField;
public MainPanel() {
setLayout(new BorderLayout());
// Set up config panel
JPanel configPanel = new JPanel();
configPanel.setLayout(new BoxLayout(configPanel, BoxLayout.X_AXIS));
configPanel.setMaximumSize(new Dimension(400, 200));
titleField = new JTextField(25);
titleField.setFont(INPUT_FONT);
topBorderField = new JTextField(1);
topBorderField.setFont(INPUT_FONT);
sideBorderField = new JTextField(4);
sideBorderField.setFont(INPUT_FONT);
configPanel.add(new JLabel("Title:"));
configPanel.add(titleField);
configPanel.add(new JLabel("Top border:"));
configPanel.add(topBorderField);
configPanel.add(new JLabel("Side border:"));
configPanel.add(sideBorderField);
add(configPanel, BorderLayout.NORTH);
// Set up Input panel
JPanel lowerPanel = new JPanel(new GridLayout(1, 1));
JPanel inputPanel = new JPanel();
inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS));
inputArea = new JTextArea("Type or paste your stuff here . . .");
inputArea.setFont(INPUT_FONT);
inputArea.setLineWrap(true);
inputArea.setWrapStyleWord(true);
inputArea.setColumns(75);
JScrollPane inputPane = new JScrollPane(inputArea);
JLabel inputLabel = new JLabel("Text Box");
inputLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
inputPanel.add(inputLabel);
inputPanel.add(inputPane);
lowerPanel.add(inputPanel);
// Set up Output panel
JPanel outputPanel = new JPanel();
outputPanel.setLayout(new BoxLayout(outputPanel, BoxLayout.Y_AXIS));
outputArea = new JTextArea();
outputArea.setFont(INPUT_FONT);
outputArea.setLineWrap(true);
outputArea.setWrapStyleWord(true);
outputArea.setColumns(75);
JScrollPane outputPane = new JScrollPane(outputArea);
JLabel outputLabel = new JLabel("Wrapped Output");
outputLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
outputPanel.add(outputLabel);
outputPanel.add(outputPane);
lowerPanel.add(outputPanel);
add(lowerPanel, BorderLayout.CENTER);
}
}
I felt it convenient to use BorderLayout for this format.Anyways, you can still make few changes to the code you posted using GridBagConstraints to get the desired look.Make the below changes one by one and you will observe the differences.
1.You were aligning the MainPanel to the NORTH by using BorderLayout.But in your case the entire set of components is placed in MainPanel,so better place it in center.So instead of NORTH use below :(after this change,you will see the complete input and output panels)
MainPanel panel = new MainPanel();
frame.getContentPane().add(panel, BorderLayout.CENTER);
2.You have set the dimension of the Parent frame to Dimension(height=375)
minSize = new Dimension(650, 375);
You components(configPanel=200,outputPanel=400) combined height is more than 375.Increase the height of the Parent, to about 600.
3.Instead of BoxLayout try using GridLayout for configPanel.
configPanel.setLayout(new GridLayout(1,6,5,0));
Making the above 3 changes to your existing code will get the expected output.Hope this clarifies.
A GUI with no white space appears 'crowded'. How can I provide white space without resorting to explicitly setting the position or size of components?
Using various LayoutManagers one can provide spacing between various components.
1.) BorderLayout :
Overloaded Constructor : BorderLayout(int horizontalGap, int verticalGap)
Getter and setter methods
For Horizontal Spacing : BorderLayout.getHgap() and BorderLayout.setHgap(int hgap)
For Vertical Spacing : BorderLayout.getVgap() and BorderLayout.setVgap()
2.) FlowLayout :
Overloaded Constructor : FlowLayout(int align, int hgap, int vgap)
Getter and setter methods
For Horizontal Spacing : FlowLayout.getHgap() and FlowLayout.setHgap(int hgap)
For Vertical Spacing : FlowLayout.getVgap() and FlowLayout.setVgap()
3.) GridLayout :
Overloaded Constructor : GridLayout(int rows, int columns, int hgap, int vgap)
Getter and setter methods
For Horizontal Spacing : GridLayout.getHgap() and GridLayout.setHgap(int hgap)
For Vertical Spacing : GridLayout.getVgap() and GridLayout.setVgap()
4.) GridBagLayout :
GridBagConstraints.insets
5.) CardLayout (example) :
CardLayout(int hGap, int vGap)
Example to display all constructors in action :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class LayoutExample {
private final int hGap = 5;
private final int vGap = 5;
private String[] borderConstraints = {
BorderLayout.PAGE_START,
BorderLayout.LINE_START,
BorderLayout.CENTER,
BorderLayout.LINE_END,
BorderLayout.PAGE_END
};
private JButton[] buttons;
private GridBagConstraints gbc;
private JPanel borderPanel;
private JPanel flowPanel;
private JPanel gridPanel;
private JPanel gridBagPanel;
private JPanel cardPanel;
public LayoutExample() {
buttons = new JButton[16];
gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.insets = new Insets(hGap, vGap, hGap, vGap);
}
private void displayGUI() {
JFrame frame = new JFrame("Layout Example");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel(
new GridLayout(0, 1, hGap, vGap));
contentPane.setBorder(
BorderFactory.createEmptyBorder(hGap, vGap, hGap, vGap));
borderPanel = new JPanel(new BorderLayout(hGap, vGap));
borderPanel.setBorder(
BorderFactory.createTitledBorder("BorderLayout"));
borderPanel.setOpaque(true);
borderPanel.setBackground(Color.WHITE);
for (int i = 0; i < 5; i++) {
buttons[i] = new JButton(borderConstraints[i]);
borderPanel.add(buttons[i], borderConstraints[i]);
}
contentPane.add(borderPanel);
flowPanel = new JPanel(new FlowLayout(
FlowLayout.CENTER, hGap, vGap));
flowPanel.setBorder(
BorderFactory.createTitledBorder("FlowLayout"));
flowPanel.setOpaque(true);
flowPanel.setBackground(Color.WHITE);
for (int i = 5; i < 8; i++) {
buttons[i] = new JButton(Integer.toString(i));
flowPanel.add(buttons[i]);
}
contentPane.add(flowPanel);
gridPanel = new JPanel(new GridLayout(2, 2, hGap, vGap));
gridPanel.setBorder(
BorderFactory.createTitledBorder("GridLayout"));
gridPanel.setOpaque(true);
gridPanel.setBackground(Color.WHITE);
for (int i = 8; i < 12; i++) {
buttons[i] = new JButton(Integer.toString(i));
gridPanel.add(buttons[i]);
}
contentPane.add(gridPanel);
gridBagPanel = new JPanel(new GridBagLayout());
gridBagPanel.setBorder(
BorderFactory.createTitledBorder("GridBagLayout"));
gridBagPanel.setOpaque(true);
gridBagPanel.setBackground(Color.WHITE);
buttons[12] = new JButton(Integer.toString(12));
addComp(gridBagPanel, buttons[12], 0, 0, 1, 1
, GridBagConstraints.BOTH, 0.33, 0.5);
buttons[13] = new JButton(Integer.toString(13));
addComp(gridBagPanel, buttons[13], 1, 0, 1, 1
, GridBagConstraints.BOTH, 0.33, 0.5);
buttons[14] = new JButton(Integer.toString(14));
addComp(gridBagPanel, buttons[14], 0, 1, 2, 1
, GridBagConstraints.BOTH, 0.66, 0.5);
buttons[15] = new JButton(Integer.toString(15));
addComp(gridBagPanel, buttons[15], 2, 0, 1, 2
, GridBagConstraints.BOTH, 0.33, 1.0);
contentPane.add(gridBagPanel);
cardPanel = new JPanel(new CardLayout(hGap, vGap));
cardPanel.setBorder(
BorderFactory.createTitledBorder("CardLayout"));
cardPanel.setOpaque(true);
cardPanel.setBackground(Color.WHITE);
cardPanel.add(getPanel(Color.BLUE));
cardPanel.add(getPanel(Color.GREEN));
contentPane.add(cardPanel);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel getPanel(Color bColor) {
JPanel panel = new JPanel(new FlowLayout(
FlowLayout.CENTER, hGap, vGap));
panel.setOpaque(true);
panel.setBackground(bColor.darker().darker());
JButton swapperButton = new JButton("Next");
swapperButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
CardLayout cardLayout = (CardLayout) cardPanel.getLayout();
cardLayout.next(cardPanel);
}
});
panel.add(swapperButton);
return panel;
}
private void addComp(JPanel panel, JComponent comp
, int x, int y, int gWidth
, int gHeight, int fill
, double weightx, double weighty) {
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = gWidth;
gbc.gridheight = gHeight;
gbc.fill = fill;
gbc.weightx = weightx;
gbc.weighty = weighty;
panel.add(comp, gbc);
}
public static void main(String[] args) {
Runnable runnable = new Runnable(){
#Override
public void run() {
new LayoutExample().displayGUI();
}
};
EventQueue.invokeLater(runnable);
}
}
OUTPUT :
There are a number of ways in a Swing GUI to provide a separation between components, and white space around components:
JToolBar has the methods addSeparator() & addSeparator(Dimension).
JMenu uses a spacing component better suited to menus, available through addSeparator().
But more generally, look to:
The spacing as can be defined in the layout constructors.
Borders.
Here is an example of using the layout separator hGap & vGap values & borders (specifically an EmptyBorder) to provide 'white' (actually shown as red to make it very obvious) space. Adjust the spinners to see the result.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.*;
public class WhiteSpace {
private JPanel gui = null;
private BorderLayout mainLayout =
new BorderLayout(0, 0);
private final FlowLayout buttonLayout =
new FlowLayout(FlowLayout.CENTER, 0, 0);
private final JPanel buttonPanel = new JPanel(buttonLayout);
private final SpinnerNumberModel hModel =
new SpinnerNumberModel(0, 0, 15, 1);
private final SpinnerNumberModel vModel =
new SpinnerNumberModel(0, 0, 15, 1);
private final SpinnerNumberModel hBorderModel =
new SpinnerNumberModel(0, 0, 15, 1);
private final SpinnerNumberModel vBorderModel =
new SpinnerNumberModel(0, 0, 15, 1);
private ChangeListener changeListener;
public Container getGui() {
if (gui == null) {
gui = new JPanel(mainLayout);
gui.setBackground(Color.RED);
JTree tree = new JTree();
tree.setVisibleRowCount(10);
for (int ii = tree.getRowCount(); ii > -1; ii--) {
tree.expandRow(ii);
}
gui.add(new JScrollPane(
tree,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER),
BorderLayout.LINE_START);
gui.add(new JScrollPane(new JTextArea(10, 30)));
gui.add(buttonPanel, BorderLayout.PAGE_START);
changeListener = (ChangeEvent e) -> {
int hGap = hModel.getNumber().intValue();
int vGap = vModel.getNumber().intValue();
int hBorder = hBorderModel.getNumber().intValue();
int vBorder = vBorderModel.getNumber().intValue();
adjustWhiteSpace(hGap, vGap, hBorder, vBorder);
};
addModel("H Gap", hModel);
addModel("V Gap", vModel);
addModel("H Border", hBorderModel);
addModel("V Border", vBorderModel);
}
return gui;
}
private void addModel(String label, SpinnerNumberModel model) {
buttonPanel.add(new JLabel(label));
final JSpinner spinner = new JSpinner(model);
spinner.addChangeListener(changeListener);
buttonPanel.add(spinner);
}
private void adjustWhiteSpace(
int hGap, int vGap, int hBorder, int vBorder) {
mainLayout.setHgap(hGap);
mainLayout.setVgap(vGap);
buttonLayout.setHgap(hGap);
gui.setBorder(new EmptyBorder
(vBorder, hBorder, vBorder, hBorder));
Container c = gui.getTopLevelAncestor();
if (c instanceof Window) {
Window w = (Window) c;
w.pack();
}
}
public static void main(String[] args) {
Runnable r = () -> {
WhiteSpace ws = new WhiteSpace();
Container gui1 = ws.getGui();
JFrame f = new JFrame("White (OK Red) Space");
f.add(gui1);
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
f.setLocationByPlatform(true);
f.setResizable(false);
f.pack();
f.setVisible(true);
};
SwingUtilities.invokeLater(r);
}
}
When you use BoxLayout, Box.createVerticalGlue() method can help you to make some white space.
Another method is BorderFactory.createEmptyBorder(int top, int left, int bottom, int right). It can help you to make some white space around component.
Thanks for Andrew Thompson's remind.I've revised BoxLayout in recent days and I find that Box.createVerticalGlue() can add some white space depend on the panel's size and you can not set the explicit pixel value of the length of white space.But Box.createVerticalStrut() can do that. Here is a MCTaRE and show the effect of those two methods.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
public class WhiteSpace extends JFrame{
static WhiteSpace whiteSpace;
DemoPanel demoPanel;
boolean withGlue;
JSpinner spinner;
public WhiteSpace(){
initialWindow();
demoPanel = new DemoPanel();
ActionPanel actionPanel = new ActionPanel();
setLayout(new BorderLayout());
getContentPane().add(actionPanel,BorderLayout.NORTH);
getContentPane().add(demoPanel,BorderLayout.CENTER);
setVisible(true);
}
public void initialWindow(){
setSize(220, 300);
setTitle("White Space");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
//Show the window in the middle of the screen
}
/**
* #param args
*/
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
whiteSpace = new WhiteSpace();
}
};
SwingUtilities.invokeLater(runnable);
}
class DemoPanel extends JPanel{
//Show the vertical white space between label1 and label2
JLabel label1;
JLabel label2;
public void initialDemoPanel(){
setBorder(BorderFactory.createTitledBorder(getBorder(), "DemoPanel", TitledBorder.LEADING, TitledBorder.TOP, new Font("Default",Font.PLAIN,10), Color.gray));
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
label1 = new JLabel("This is first line");
label2 = new JLabel("This is second line");
}
public DemoPanel(){
initialDemoPanel();
add(label1);
if(withGlue){
add(Box.createVerticalGlue());
}
add(label2);
}
public DemoPanel(int strutValue){
initialDemoPanel();
add(label1);
add(Box.createVerticalStrut(strutValue));
add(label2);
}
}
class ActionPanel extends JPanel{
public ActionPanel(){
setBorder(BorderFactory.createTitledBorder(getBorder(), "ActionPanel", TitledBorder.LEADING, TitledBorder.TOP, new Font("Default",Font.PLAIN,10), Color.gray));
setLayout(new BoxLayout(this,BoxLayout.X_AXIS));
JRadioButton glueButton = new JRadioButton("With Glue");
glueButton.addActionListener(new glueButtonListener());
add(glueButton);
add(Box.createHorizontalStrut(10));
//To create horizontal white space
JLabel strutLabel = new JLabel("Strut Value");
add(strutLabel);
spinner = new JSpinner(new SpinnerNumberModel(0,0,50,1));
spinner.addChangeListener(new spinnerListener());
add(spinner);
//public SpinnerNumberModel(Number value,Comparable minimum,Comparable maximum,Number stepSize)
}
}
class glueButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
spinner.setValue(new Integer(0));
withGlue = (withGlue == true ? false:true);
whiteSpace.getContentPane().remove(demoPanel);
demoPanel = new DemoPanel();
whiteSpace.getContentPane().add(demoPanel,BorderLayout.CENTER);
whiteSpace.getContentPane().validate();
}
}
class spinnerListener implements ChangeListener{
#Override
public void stateChanged(ChangeEvent e) {
int strutValue = (Integer) spinner.getValue();
whiteSpace.getContentPane().remove(demoPanel);
demoPanel = new DemoPanel(strutValue);
whiteSpace.getContentPane().add(demoPanel,BorderLayout.CENTER);
whiteSpace.getContentPane().validate();
}
}
}
Box.createHorizontalGlue() and Box.createHorizontalStrut(int height) can be used too. Besides, Box.createRigidArea(Dimension d) has the ability too create white space too.
MigLayout has multiple ways of creating space. (A space is called a gap in this layout.)
Gaps can be created at the highest level with layout constraints, it is possible to
create gaps between rows and column and gaps can be also set between individual
components with component constraints. There are also specific gaps around the borders
of a container called insets which have their own specific keyword to be set.
The following example creates all these kinds of gaps:
package com.zetcode;
import java.awt.EventQueue;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import net.miginfocom.swing.MigLayout;
public class MigLayoutGaps2 extends JFrame {
public MigLayoutGaps2() {
initUI();
setTitle("Gaps");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
}
private void initUI() {
JPanel base = new JPanel(new MigLayout("flowy, ins 30, gap 15"));
setContentPane(base);
JPanel pnl1 = new JPanel();
pnl1.setBorder(
BorderFactory.createTitledBorder("Grid gaps")
);
pnl1.setLayout(new MigLayout("gap 5 5, ins 10, wrap 3"));
pnl1.add(new JButton("1"));
pnl1.add(new JButton("2"));
pnl1.add(new JButton("3"));
pnl1.add(new JButton("4"));
pnl1.add(new JButton("5"));
pnl1.add(new JButton("6"));
JPanel pnl2 = new JPanel();
pnl2.setBorder(
BorderFactory.createTitledBorder("Column gaps")
);
pnl2.setLayout(new MigLayout("wrap 3", "[]10[]"));
JLabel lbl1 = new JLabel();
lbl1.setBorder(
BorderFactory.createEtchedBorder()
);
JLabel lbl2 = new JLabel();
lbl2.setBorder(
BorderFactory.createEtchedBorder()
);
JLabel lbl3 = new JLabel();
lbl3.setBorder(
BorderFactory.createEtchedBorder()
);
pnl2.add(lbl1, "w 40, h 110");
pnl2.add(lbl2, "w 40, h 110");
pnl2.add(lbl3, "w 40, h 110");
JPanel pnl3 = new JPanel();
pnl3.setBorder(
BorderFactory.createTitledBorder("Row gaps")
);
pnl3.setLayout(new MigLayout("wrap", "", "[]15[]"));
JLabel lbl4 = new JLabel();
lbl4.setBorder(
BorderFactory.createEtchedBorder()
);
JLabel lbl5 = new JLabel();
lbl5.setBorder(
BorderFactory.createEtchedBorder()
);
JLabel lbl6 = new JLabel();
lbl6.setBorder(
BorderFactory.createEtchedBorder()
);
pnl3.add(lbl4, "w 150, h 20");
pnl3.add(lbl5, "w 150, h 20");
pnl3.add(lbl6, "w 150, h 20");
JPanel pnl4 = new JPanel();
pnl4.setBorder(
BorderFactory.createTitledBorder("Component gaps")
);
pnl4.setLayout(new MigLayout());
pnl4.add(new JLabel("Name:"), "gapright 5");
pnl4.add(new JTextField(10), "gapbottom 20, gaptop 20");
base.add(pnl1);
base.add(pnl2);
base.add(pnl3);
base.add(pnl4);
pack();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
MigLayoutGaps2 ex = new MigLayoutGaps2();
ex.setVisible(true);
}
});
}
}
We have four panels in the layout. Each of this panels has a MigLayout manager.
JPanel base = new JPanel(new MigLayout("flowy, ins 30, gap 15"));
This line creates container insets and vertical gaps between panels.
pnl1.setLayout(new MigLayout("gap 5 5, ins 10, wrap 3"));
Here we apply gaps for the whole grid structure and also set container gaps.
pnl2.setLayout(new MigLayout("wrap 3", "[]10[]"));
This line creates gaps between columns.
pnl3.setLayout(new MigLayout("wrap", "", "[]15[]"));
Row gaps are defined with this code.
pnl4.add(new JLabel("Name:"), "gapright 5");
pnl4.add(new JTextField(10), "gapbottom 20, gaptop 20");
Finally, it is possible to create gaps between individual components.
JGoodies FormLayout.
Author Karsten Lentzsch has a collection of presentations on UI design. In particular this PDF speaks to the need for aesthetic whitespace. Adding meaningful space while also paying attention to clutter separates the wheat from the chaff.
Whenever I have this issue, I just use JPanels. For example in a GridLayout:
JFrame frame = new JFrame;
frame.setLayout(new GridLayout(2, 0));
//We want the bottom left to be blank
frame.add(new JLabel("Top Left"));
frame.add(new JLabel("Top Right"));
//This is the position we want empty
frame.add(new JPanel());
//Now we can continue with the rest of the script
i have to writing an applet, in left side i must use an panel to contain a list of vehicles that can be a list of buttons,what is the problem, number of the vehicles are not given !!!
so, i need to scrolling panel when number of vehicles is too much,
i do this for jframe, but it didn't work correct with panel, please help me with an example
the code i use to scrolling panel is :
public class VehicleList extends JPanel {
private ArrayList<VehicleReport> vehicles;
private ArrayList<JButton> v_buttons = new ArrayList<JButton>();
public void showList(ArrayList<Vehicles> vehicles)
{
this.vehicles = vehicles;
//...
add(getScrollpane());
setSize(155,300);
}
public JScrollPane getScrollpane()
{
JPanel panel = new JPanel();
panel.setPreferredSize(new DimensionUIResource(150, 300));
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints constraint = new GridBagConstraints();
panel.setLayout(gridbag);
constraint.fill = GridBagConstraints.HORIZONTAL;
JLabel title = new JLabel("Vehiles list");
constraint.gridwidth = 2;
constraint.gridx = 0;
constraint.gridy = 0;
constraint.ipady = 230;
gridbag.setConstraints(title, constraint);
panel.add(title);
// end of set title
constraint.gridwidth = 1;
int i=1;
for(JButton jb : v_buttons )
{
constraint.gridx =0;
constraint.gridy = i;
gridbag.setConstraints(jb, constraint);
panel.add(jb);
JLabel vehicle_lable = new JLabel("car" + i);
constraint.gridx = 1;
constraint.gridy = i;
gridbag.setConstraints(vehicle_lable, constraint);
panel.add(vehicle_lable);
i++;
}
JScrollPane jsp = new JScrollPane(panel);
return jsp;
}
}
in jaframe after add jscrollpane to jframe i place this
pack();
setSize(250, 250);
setLocation(100, 300);
and it work clearly!!!!
You also don't show us the layout manager of the VehicleList JPanel. In case you aren't setting it, it defaults to FlowLayout, unlike JFrame (which you mentioned this does work in), whose content pane defaults to BorderLayout. So maybe you just need to change the relevant code from:
//...
add(getScrollpane());
to
//...
setLayout(new BorderLayout());
add(getScrollpane(), BorderLayout.CENTER);
You need to set the scrolling policy on the horizontal and vertical:
public void setHorizontalScrollBarPolicy(int policy)
public void setVerticalScrollBarPolicy(int policy)
Using:
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS
And:
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
JScrollPane.VERTICAL_SCROLLBAR_NEVER
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS
So for example:
jscrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);