GridBagLayout in JPanel, components don't change x || y positions - java

I'm attempting to create my own GUI, trying to move the playerWins JLabel over to the far right. I've tried changing both x and y coordinates but the JLabel stays where it is. I'm wondering if it has to do with the JPanel being set as CENTRE.
import javax.swing.*;
import java.awt.*;
public class DieIntGUI extends JFrame {
public DieIntGUI(String title) {
super(title);
setSize(700, 700);
getContentPane().setBackground(Color.white);
setLayout(new BorderLayout());
initComponents();
add(panel);
add(errorMessages, BorderLayout.SOUTH);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
DieIntGUI frame = new DieIntGUI("Dice Game");
frame.setVisible(true);
}
private void initComponents() {
panel = new JPanel();
errorMessages = new JLabel("T");
playerWins = new JLabel("F");
computerWins = new JLabel("S");
drawComponents();
}
private void drawComponents() {
GridBagConstraints gbc = new GridBagConstraints();
panel.setLayout(new GridBagLayout());
panel.setSize(700, 700);
panel.setBackground(Color.white);
gbc.gridx = 2;
gbc.gridy = 17;
panel.add(playerWins, gbc);
}
private JPanel panel;
private JLabel errorMessages;
public JLabel playerWins, computerWins;
}

The solution using GridBagLayout would be.
gbc.gridx = 1;
gbc.gridy = 1;
gbc.weightx=1; //Fill all space
gbc.anchor=GridBagConstraints.EAST; //align component to the EAST
I have set x, y to 1. What's important to understand is that these are index's relative to other object that you add. (Has no sense if only 1 component, there are no invisible grid locations.)

This will move the label to far right.
public DieIntGUI(String title) {
super(title);
setSize(700, 700);
getContentPane().setBackground(Color.white);
setLayout(new BorderLayout());
initComponents();
add(panel, BorderLayout.EAST); // Move to right
add(errorMessages, BorderLayout.SOUTH);
setLocationRelativeTo(null);
}
Output:
And yes, the panel was set to CENTER because in BorderLayout, if you do not specify a position, its set to BorderLayout.CENTER by default.

Related

Resizing of multiple JPanels to fit window

I'm pretty new to the Java Swing toolkit and have created a series of JPanel with JLabel components corresponding to each panel's index and value. However I can’t seem to make the panels correctly resize, when the window is too small to resize all the panels at once. Resulting in the an extra red margin to the right of all the panels (See. Window).
Is there a way to make the Sub Panels/Spacer Panels resize in such a way that does not allow for the extra margin? Or setup a better swing layout to handle such resizing?
Code demo:
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.BoxLayout;
public class Frame extends JFrame {
private int numBox = 20;
public class SubPanel extends JPanel {
public SubPanel(int i) {
setMinimumSize(new Dimension(20, 20));
setMaximumSize(new Dimension(1000, i*30));
setBackground(Color.BLACK);
setLayout(new BorderLayout());
setAlignmentY(Component.BOTTOM_ALIGNMENT);
JLabel labelValue = new JLabel(String.valueOf(30 * i), JLabel.CENTER);
labelValue.setForeground(Color.WHITE);
add(labelValue, BorderLayout.NORTH);
JLabel labelIndex = new JLabel(String.valueOf(i), JLabel.CENTER);
labelIndex.setForeground(Color.WHITE);
add(labelIndex, BorderLayout.SOUTH);
}
}
public class SpacerPanel extends JPanel {
public SpacerPanel() {
setBackground(Color.WHITE);
setMaximumSize(new Dimension(3, 10000));
setMinimumSize(new Dimension(3, 0));
}
}
public Frame(String title) {
super(title);
JPanel mainPanel = new JPanel();
mainPanel.setBackground(Color.RED);
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.LINE_AXIS));
for (int i = 1; i < numBox + 1; i++) {
mainPanel.add(new SpacerPanel());
mainPanel.add(new SubPanel(i));
}
mainPanel.add(new SpacerPanel());
add(mainPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new Frame("Frame").setSize(1200, 700);
}
}
If you have 40 components and you resize the frame by a few pixels, the BoxLayout is having problems allocating those pixels to each of the components.
Instead you can use the Relative Layout which allows you to specify how those pixels should be allocated.
The RelativeLayout also allows you to specify a gap between each component so you don't need to add the SpacerPanel.
However, you will need to modify the logic of the "subPanel". The height of the labels needs to be fixed so they can be painted black. So I created a "labelPanel" to hold the labels.
The restructured code using the RelativeLayout would be:
import java.awt.*;
import javax.swing.*;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.BoxLayout;
public class Frame extends JFrame {
private int numBox = 20;
public class SubPanel extends JPanel {
public SubPanel(int i) {
// setMinimumSize(new Dimension(20, 20));
// setMaximumSize(new Dimension(1000, i*30));
// setPreferredSize(new Dimension(20, i*30));
setBackground(Color.RED);
setLayout(new BorderLayout());
// setAlignmentY(Component.BOTTOM_ALIGNMENT);
JPanel labelPanel = new JPanel( new BorderLayout() );
labelPanel.setBackground( Color.BLACK );
labelPanel.setPreferredSize(new Dimension(20, i*30));
add(labelPanel, BorderLayout.PAGE_END);
JLabel labelValue = new JLabel(String.valueOf(30 * i), JLabel.CENTER);
labelValue.setForeground(Color.WHITE);
labelPanel.add(labelValue, BorderLayout.NORTH);
JLabel labelIndex = new JLabel(String.valueOf(i), JLabel.CENTER);
labelIndex.setForeground(Color.WHITE);
labelPanel.add(labelIndex, BorderLayout.SOUTH);
}
}
public class SpacerPanel extends JPanel {
public SpacerPanel() {
setBackground(Color.WHITE);
setMaximumSize(new Dimension(3, 10000));
setMinimumSize(new Dimension(3, 0));
}
}
public Frame(String title) {
super(title);
JPanel mainPanel = new JPanel();
// mainPanel.setBackground(Color.RED);
mainPanel.setBackground(Color.WHITE);
// mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.LINE_AXIS));
RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS, 5);
rl.setFill( true );
rl.setRoundingPolicy(RelativeLayout.EQUAL);
rl.setAlignment(RelativeLayout.TRAILING);
mainPanel.setLayout( rl );
Float constraint = new Float(1);
for (int i = 1; i < numBox + 1; i++) {
// mainPanel.add(new SpacerPanel());
// mainPanel.add(new SubPanel(i));
mainPanel.add(new SubPanel(i), constraint);
}
// mainPanel.add(new SpacerPanel());
add(mainPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new Frame("Frame").setSize(1200, 700);
}
}
Or this approach is closer to your original posting. It still uses the spacer and the height of the black columns will shrink as the frame height is decreased:
import java.awt.*;
import javax.swing.*;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.BoxLayout;
public class Frame2 extends JFrame {
private int numBox = 20;
public class SubPanel extends JPanel {
public SubPanel(int i) {
// setMinimumSize(new Dimension(20, 20));
// setMaximumSize(new Dimension(1000, i*30));
// setBackground(Color.BLACK);
setBackground(Color.RED);
// setLayout(new BorderLayout());
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(Box.createVerticalGlue());
// setAlignmentY(Component.BOTTOM_ALIGNMENT);
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.Y_AXIS));
labelPanel.setBackground( Color.BLACK );
labelPanel.setPreferredSize(new Dimension(50, i*30));
labelPanel.setMaximumSize(new Dimension(1000, labelPanel.getPreferredSize().height));
add(labelPanel, BorderLayout.CENTER);
JLabel labelValue = new JLabel(String.valueOf(30 * i), JLabel.CENTER);
labelValue.setForeground(Color.WHITE);
labelValue.setAlignmentX(JLabel.CENTER_ALIGNMENT);
// add(labelValue, BorderLayout.NORTH);
labelPanel.add(labelValue);
labelPanel.add(Box.createVerticalGlue());
JLabel labelIndex = new JLabel(String.valueOf(i), JLabel.CENTER);
labelIndex.setForeground(Color.WHITE);
labelIndex.setAlignmentX(JLabel.CENTER_ALIGNMENT);
// add(labelIndex, BorderLayout.SOUTH);
labelPanel.add(labelIndex);
}
}
public class SpacerPanel extends JPanel {
public SpacerPanel() {
setBackground(Color.WHITE);
setMaximumSize(new Dimension(3, 10000));
setMinimumSize(new Dimension(3, 0));
}
}
public Frame2(String title) {
super(title);
JPanel mainPanel = new JPanel();
mainPanel.setBackground(Color.RED);
// mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.LINE_AXIS));
RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS, 0);
rl.setFill( true );
rl.setRoundingPolicy(RelativeLayout.EQUAL);
rl.setAlignment(RelativeLayout.TRAILING);
mainPanel.setLayout( rl );
Float constraint = new Float(1);
for (int i = 1; i < numBox + 1; i++) {
mainPanel.add(new SpacerPanel());
// mainPanel.add(new SubPanel(i));
mainPanel.add(new SubPanel(i), constraint);
}
mainPanel.add(new SpacerPanel());
add(mainPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new Frame2("Frame").setSize(1200, 700);
}
}

How to align vertically buttons of different sizes within a GridBagLayout?

I'm starting with swing, I have some questions about how to align elements within a GridBagLayout, I'm not sure either whether this is the correct approach, please advice.
I have the below code
import javax.swing.*;
import java.awt.*;
public class App {
public void start() {
JPanel mainPanel = new JPanel(new FlowLayout());
mainPanel.setBorder(BorderFactory.createLineBorder(Color.CYAN, 20));
//buttons for initial options
JButton button1 = new JButton("This is option A");
JButton button2 = new JButton("option B");
JButton button3 = new JButton("Another text");
JPanel second = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.CENTER;
second.setBackground(Color.GREEN);
second.add(button1, gbc);
second.add(button2, gbc);
second.add(button3, gbc);
mainPanel.add(second, BorderLayout.CENTER);
//frame configuration
JFrame frame = new JFrame();
frame.setContentPane(mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setResizable(false);
}
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
SwingUtilities.invokeLater(() -> new App().start());
}
}
My goal is to produce the following output:
So far I have tried with BoxLayout with vertical alignment and it works but the problem is that it overwrites the preferred sized of the buttons and I want them all to be the same width.
Also, I tried with GridLayout and BorderLayout adding the elements to NORTH, CENTER, and SOUTH but the sizes of the buttons change.
What is the recommended way to center the elements but keeping their dimensions?
I would nest layouts:
A JPanel that holds the buttons and uses a new GridLayout(0, 1, 0, vGap) -- a grid that holds one column and variable number of rows, with a vGap gap between buttons.
Add that JPanel into another JPanel that uses GridBagLayout, and add it in a default way (no GridBagConstraints) which will center the first JPanel into the second. This would obviously have to somehow be the size desired. This can be achieved by either
overriding getPreferredSize() in a sensible way
Calling setPreferredSize(new Dimension(someWidth, someHeight)) -- this isn't quite as "clean"
Giving this a border, specifically a BorderFactor.EmptyBorder(gap, gap, gap, gap) where gap is the size of the border around the JPanel...
Done.
Test code that uses the GridBagLayout:
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import javax.swing.*;
public class ButtonLayout extends JPanel {
public static final int MY_WIDTH = 750;
public static final int MY_HEIGHT = 500;
private static final float BTN_SIZE = 24f;
private String[] buttonTexts = {"This is Option A", "Option B",
"Something Else Entirely"};
public ButtonLayout() {
int colGap = 20;
JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 0, colGap));
for (String btnText : buttonTexts) {
JButton button = new JButton(btnText);
// set first letter of text as mnemonic (alt-char shortcut)
int mnemonic = (int) btnText.charAt(0);
button.setMnemonic(mnemonic);
// make button bigger by increasing its font
button.setFont(button.getFont().deriveFont(BTN_SIZE));
// add to the GridLayout-using JPanel
buttonPanel.add(button);
}
// set layout of main panel to GridBag
setLayout(new GridBagLayout());
// add the button panel in a "default" manner (no constraints)
// which centers this panel
add(buttonPanel);
}
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
int width = Math.max(MY_WIDTH, superSize.width);
int height = Math.max(MY_HEIGHT, superSize.height);
return new Dimension(width, height);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
ButtonLayout mainPanel = new ButtonLayout();
JFrame frame = new JFrame("ButtonLayout");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Example 2 that uses EmptyBorder:
import java.awt.GridLayout;
import javax.swing.*;
#SuppressWarnings("serial")
public class ButtonLayout extends JPanel {
public static final int MY_WIDTH = 750;
public static final int MY_HEIGHT = 500;
private static final float BTN_SIZE = 24f;
private String[] buttonTexts = {"This is Option A", "Option B",
"Something Else Entirely"};
public ButtonLayout() {
int colGap = 20;
JPanel buttonPanel = new JPanel(new GridLayout(0, 1, 0, colGap));
for (String btnText : buttonTexts) {
JButton button = new JButton(btnText);
// set first letter of text as mnemonic (alt-char shortcut)
int mnemonic = (int) btnText.charAt(0);
button.setMnemonic(mnemonic);
// make button bigger by increasing its font
button.setFont(button.getFont().deriveFont(BTN_SIZE));
// add to the GridLayout-using JPanel
buttonPanel.add(button);
}
add(buttonPanel);
int top = 60;
int left = top;
int bottom = 2 * top;
int right = left;
setBorder(BorderFactory.createEmptyBorder(top, left, bottom, right));
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
ButtonLayout mainPanel = new ButtonLayout();
JFrame frame = new JFrame("ButtonLayout");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
I'm not sure I completely understand the issue, but if you want to vertically align the buttons, BUT allow them to keep their preferred size, just don't provide any kind of fill constraint, for example
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SoTest {
public static void main(String[] args) {
new SoTest();
}
public SoTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
add(new JButton("This is option A"), gbc);
add(new JButton("Option B"), gbc);
add(new JButton("Another button"), gbc);
}
}
}
Or, if you want them to have the same width, use a fill constraint
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SoTest {
public static void main(String[] args) {
new SoTest();
}
public SoTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.BOTH;
add(new JButton("This is option A"), gbc);
add(new JButton("Option B"), gbc);
add(new JButton("Another button"), gbc);
}
}
}
If you want to mix a more complex layout, then you should consider making use of compound layouts
But wait, there's no outline...
So, a number of ways you "might" be able to do this, for example, you could use a CompoundBorder....
setBorder(new CompoundBorder(new LineBorder(Color.CYAN, 16), new EmptyBorder(32, 32, 32, 32)));
But the devil is in the detail

Textarea maximalsize in Borderlayout

I have a simple problem but I found no good solution for it. I have a JFrame with components at SOUTH, NORTH, EAST, and CENTER. On CENTER is my problem. On center I have a JPanel with a Borderlayout and 2 JTextAreas (one on NORTH, one int the CENTER).
I want that the first panel begins always on top of the panel and stretch maximum (if needed) to the middle of the panel, not more. The second area should begin at the end of the first area. If one of both text areas is to big, there should appear a JScrollPane.
What is the best Way to realize that? Should I use a other layout for the panel?
Here is my little execute example for it:
public class myGUI {
public static void main(String[] args) {
new myGUI();
}
public myGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
//Add Content at South, West and North....
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new BorderLayout());
centerPanel.add(new JScrollPane(new JTextArea("AREA")), BorderLayout.NORTH);
centerPanel.add(new JScrollPane(new JTextArea("AREA2")), BorderLayout.CENTER);
frame.add(centerPanel);
frame.setVisible(true);
}
}
Possible scenarios of the center panel:
SOLUTION with help from #Hovercraft Full Of Eels
public class MyGUI {
public static void main(String[] args) {
new MyGUI();
}
private static GridBagConstraints constraint = new GridBagConstraints();
public MyGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.add(new JLabel("NORTH!"), BorderLayout.NORTH);
frame.add(new JLabel("EAST!"), BorderLayout.EAST);
frame.add(new JLabel("SOUTH!"), BorderLayout.SOUTH);
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new GridBagLayout());
changeConstraint(0,0);
JTextArea text1 = createTextArea("11111111111111");
centerPanel.add(text1, constraint);
changeConstraint(0,1);
JTextArea text2 = createTextArea("2222222222222");
centerPanel.add(text2, constraint);
JScrollPane scroll = new JScrollPane(centerPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
frame.add(scroll, BorderLayout.CENTER);
frame.setVisible(true);
}
/**
* Create a Gridbag Constraint
* #param text
* #return
*/
private void changeConstraint(int gridx, int gridy){
constraint.anchor = GridBagConstraints.FIRST_LINE_START;
constraint.fill = GridBagConstraints.HORIZONTAL;
constraint.weighty = 0;
constraint.weightx = 1.0;
constraint.gridx = gridx;
constraint.gridy = gridy;
}
/**
* Create a Textarea
* #param text
* #return
*/
private JTextArea createTextArea(String text){
JTextArea textarea = new JTextArea(text);
textarea.setWrapStyleWord(true);
textarea.setLineWrap(true);
return textarea;
}
}
One possibility: Consider creating a JPanel that uses GridBagLayout, and adding both JTextAreas to this JPanel, making sure to set their weightx to 0 and weighty to a non-zero value, say 1.0. Then place that JPanel into a JScrollPane and the JScrollPane into your GUI.

How to make jLabels stay attached to the corners of a window form, despite resizing the form in java?

I have 4 jLabels in my java program, which i placed in 4 corners I want them to stay there despite user resizing the window. I have written the code for the labels, but cannot seem to figure out how to keep them glued to each corner.
here is my code for the jLabels
JLabel label_1 = new JLabel("");
label_1.setEnabled(false);
label_1.setBounds(0, 0, 19, 19);
contentPane.add(label_1);
JLabel label_2 = new JLabel("");
label_2.setEnabled(false);
label_2.setBounds(0, 242, 19, 19);
contentPane.add(label_2);
JLabel label_3 = new JLabel("");
label_3.setEnabled(false);
label_3.setBounds(549, 242, 19, 19);
contentPane.add(label_3);
JLabel label_4 = new JLabel("");
label_4.setEnabled(false);
label_4.setBounds(549, 0, 19, 19);
contentPane.add(label_4);
Thanks
Don't use null layouts
Don't use setBounds(...)
Do use proper layout managers. Read the Layout Manager Tutorials for all the gory details.
Note that by using a null layout and setBounds, you ham-string your application's layout to being very rigid, very difficult to debug, enhance, and modify, and you also create a GUI that might look good on your box, but likely will not look good on another box using a different OS, or even the same OS with a slightly different screen resolution.
For example, using a GridBagLayout:
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.*;
import static java.awt.GridBagConstraints.*;
public class LabelLayout extends JPanel {
private static final int[] ANCHORS = {NORTHWEST, SOUTHWEST, NORTHEAST, SOUTHEAST};
public LabelLayout() {
setLayout(new GridBagLayout());
for (int i = 0; i < ANCHORS.length; i++) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = i / 2;
gbc.gridy = i % 2;
gbc.gridheight = 1;
gbc.gridwidth = 1;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.anchor = ANCHORS[i];
add(new JLabel("Label " + (i + 1)), gbc);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Labels");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new LabelLayout());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
A couple other notes:
I try to avoid using GridBagLayouts since they are one of the more complex layouts, but for your problem, they work nicely and simply.
Your problem can also be solved by using nested JPanels each using a simpler layout such as a BorderLayout.
Demo program, iteration number 2 that shows two GUI's, one using GridBagLayout and the other using nested JPanels, each using BorderLayout:
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.*;
import static java.awt.GridBagConstraints.*;
public class LabelLayout {
private static final int[] ANCHORS = { NORTHWEST, NORTHEAST, SOUTHWEST,
SOUTHEAST };
private JPanel gridBagPanel = new JPanel(new GridBagLayout());
private JPanel borderPanel = new JPanel(new BorderLayout());
public LabelLayout() {
for (int i = 0; i < ANCHORS.length; i++) {
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = i % 2;
gbc.gridy = i / 2;
gbc.gridheight = 1;
gbc.gridwidth = 1;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.anchor = ANCHORS[i];
gridBagPanel.add(new JLabel("Label " + (i + 1)), gbc);
}
JPanel northPanel = new JPanel(new BorderLayout());
JPanel southPanel = new JPanel(new BorderLayout());
northPanel.add(new JLabel("Label 1"), BorderLayout.WEST);
northPanel.add(new JLabel("Label 2"), BorderLayout.EAST);
southPanel.add(new JLabel("Label 3"), BorderLayout.WEST);
southPanel.add(new JLabel("Label 4"), BorderLayout.EAST);
borderPanel.add(northPanel, BorderLayout.NORTH);
borderPanel.add(southPanel, BorderLayout.SOUTH);
}
public JPanel getGridBagPanel() {
return gridBagPanel;
}
public JPanel getBorderPanel() {
return borderPanel;
}
private static void createAndShowGui() {
LabelLayout labelLayout = new LabelLayout();
JFrame frame = new JFrame("Label GridBagLayout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(labelLayout.getGridBagPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
frame = new JFrame("Label BorderLayout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(labelLayout.getBorderPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

GridBagLayout Don't make components "jump" after add

I want to use GridBagLayout for a layout that has <= 3 columns, and a variable amount of rows(If anyone knows another layout that can do this easily, please tell me), everytime I press the "add" button a square will be added at the first location that is available. Like so:
|x x x|
|x x x|
|x o |
The x's are squares, and when I press add a new square should be added where the o is now.
I managed to "kind of make it work" like so:
public void addSquare(Square square) {
c.fill = GridBagConstraints.NONE;
c.gridx = nrOfSquares % 3;
c.gridy = (int) (nrOfSquares / 3);
c.weighty = 1;
c.weightx = 1;
c.anchor = GridBagConstraints.NORTHWEST;
c.insets = new Insets(5, 5, 5, 5);
this.container.add(square, c);
this.container.revalidate();
++nrOfSquares;
}
the problem is that the second square I add is added like this:
|x x |
please note that there is an extra space between the first square and the second one. I have the same problem when an extra row is added.
Now how do I fix my code so that the squares don't "jump" and are added like in the first example I gave?
EDIT: as requested, a better example after I converted it to a regular GridLayout:
public class Square extends JPanel {
public Square() {
super();
Dimension SIZE = new Dimension(200, 200);
this.setSize(SIZE);
this.setPreferredSize(SIZE);
this.setMinimumSize(SIZE);
this.setMaximumSize(SIZE);
this.setBackground(Color.ORANGE);
this.setVisible(true);
}
}
public class SquareContainer extends JPanel {
protected JPanel realContainer;
public SquareContainer(int width, int height) {
super();
this.setLayout(new BorderLayout());
this.setBackground(Color.WHITE);
this.setSize(width, height);
this.realContainer = new JPanel();
GridLayout layout = new GridLayout(0, 3);
layout.setHgap(10);
layout.setVgap(10);
this.realContainer.setLayout(layout);
this.realContainer.setBackground(this.getBackground());
JScrollPane scroller = new JScrollPane(this.realContainer);
scroller.getVerticalScrollBar().setUnitIncrement(20);
this.add(scroller, BorderLayout.CENTER);
}
public void addSquare(Square square) {
this.realContainer.add(square);
this.realContainer.revalidate();
}
}
And I just add that to a JFrame:
public class TheGreatFrame extends JFrame {
public TheGreatFrame() {
super();
this.setSize(800, 800);
this.setLocationRelativeTo(null);
this.setLayout(new BorderLayout());
this.setResizable(false);
this.add(new SquareContainer(750, 660), BorderLayout.CENTER);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.setVisible(true);
}
}
A small example program of using GridLayout:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridLayoutEg {
private static void createAndShowGui() {
final JPanel centerPanel = new JPanel(new GridLayout(0, 3));
JButton addBtn = new JButton(new AbstractAction("Add Button") {
#Override
public void actionPerformed(ActionEvent e) {
centerPanel.add(new JButton("X"));
centerPanel.revalidate();
centerPanel.repaint();
SwingUtilities.getWindowAncestor(centerPanel).pack();
}
});
JPanel btnPanel = new JPanel();
btnPanel.add(addBtn);
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(centerPanel, BorderLayout.CENTER);
mainPanel.add(btnPanel, BorderLayout.PAGE_END);
JFrame frame = new JFrame("GridLayoutEg");
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(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
if all JComponents could have the same HEIGHT and WEIGHT, then look for GridLayout
in case that the JComponent couldn't same WEIGHT, then put each "line" to the separate JPanel (by using BorderLayout or BoxLayout) and use GridLayout for put these JPanels into Container

Categories

Resources