GridBagLayout Don't make components "jump" after add - java

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

Related

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

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

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.

JScrollPane does not react to scrollRectToVisible

I have the following window:
public class MyWindows extends JFrame {
private final JScrollPane pane;
public MyWindows(){
super();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JPanel panel = new JPanel();
pane = new JScrollPane(panel);
pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
JButton left = new JButton("<");
left.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
moveLeft();
}
});
cp.add(left, BorderLayout.WEST);
panel.setLayout(new GridLayout(1,0));
for(int i = 1; i<20; i++) {
panel.add(new JButton("hallo nummer "+i));
}
cp.add(pane, BorderLayout.CENTER);
JButton right = new JButton(">");
cp.add(right, BorderLayout.EAST);
this.setLocationRelativeTo(null);
pack();
this.setSize(300, 100);
}
private void moveLeft() {
Rectangle rec = pane.getVisibleRect();
rec.setLocation((int)(rec.getX()+1000), (int)rec.getY());
System.out.println(rec);
pane.scrollRectToVisible(rec);
System.out.println(pane.getVisibleRect());
}
}
The idea was to scroll along the buttons in the center, using the buttons on the left and on the right.
Unfortunately, the moveLeft()-Method does exactly nothing when it comes to scrolling.
The target-rectangle is java.awt.Rectangle[x=1000,y=0,width=202,height=61]
To me, that looks like a rectangle the ScrollPane should be able to scroll to.
What am I missing?
Also, sorry about the wall of code, but I just have no idea where the error may be.
Call scrollRectToVisible method on desired component (JPanel in your case) but on JScrollPane object.
private JPanel panel;
...
private void moveLeft() {
Rectangle rec = panel.getVisibleRect();
rec.setLocation((int) (rec.getX() + 1000), (int) rec.getY());
System.out.println(rec);
panel.scrollRectToVisible(rec);
System.out.println(panel.getVisibleRect());
}

JPanel of larger size than the Scrollpane

I have implemented a dialog in which I add a number of checkboxes in a JPanel that also has a scroll bar. The number of check boxes isn't fixed for each run of my program but I know it before I create the dialog.
Unfortunately when I have a large number of checkboxes to add the dialog looks like this:
My code is:
JPanel listPanel = new JPanel(new GridLayout(files.size() + 2, 1));
for (int i = 0; i < files.size(); i++) {
listPanel.add(files.get(i));
}
listPanel.setPreferredSize(new Dimension(600, 1400));
JScrollPane sp =
new JScrollPane(listPanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
sp.setPreferredSize(new Dimension(300, 200));
mainPanel.add(sp, BorderLayout.CENTER);
mainPanel.add(buttonPane, BorderLayout.EAST);
getContentPane().setLayout(new FlowLayout());
getContentPane().add(mainPanel);
pack();
setResizable(false);
How can I just set the size of the Panel inside the Scrollpane to a larger size without affecting the frame?
Avoid using setPreferredSize, let the layout managers decide the sizes they actually need...
Updated with example
The JViewport of the scroll pane is using the preferred size of the listPane to determine how much viewable space it needs, which is a lot...
In order to overcome this, you need to provide a better hint to the view port as to the viewable size your component would actually like to be. The preferredSize of the component isn't going to work here, you need to supply preferredScrollableViewportSize from the Scrollable interface
public class BadList {
public static void main(String[] args) {
new BadList();
}
public BadList() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
List<String> files = new ArrayList<>(2000);
for (int index = 0; index < 2000; index++) {
files.add(Integer.toString(index));
}
ListPane listPanel = new ListPane();
listPanel.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.weightx = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
for (String file : files) {
listPanel.add(new JCheckBox(file), gbc);
}
JScrollPane sp = new JScrollPane(listPanel);
JPanel mainPanel = new JPanel(new BorderLayout());
JPanel buttonPane = new JPanel(new GridBagLayout());
buttonPane.add(new JButton("Select All"), gbc);
buttonPane.add(new JButton("Deselect All"), gbc);
gbc.weighty = 1;
buttonPane.add(new JPanel(), gbc);
mainPanel.add(sp, BorderLayout.CENTER);
mainPanel.add(buttonPane, BorderLayout.EAST);
setLayout(new BorderLayout());
add(mainPanel);
}
}
public class ListPane extends JPanel implements Scrollable {
#Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(200, 200);
}
#Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}
#Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 128;
}
#Override
public boolean getScrollableTracksViewportWidth() {
return false;
}
#Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
}
nb- I've used some arbitrary magic numbers in this example, you're going to what to provide more realistic values for your need
JPanel has implemented FlowLayout,
FlowLayout accepting only PreferredSize, then your JScrollPane is correctly layed
use JTable (put there Boolean value, representing JCheckBox) instead of add childs to the JPanel (non_natural scrolling, have to change scroll increment)
listPanel.setPreferredSize(new Dimension(600, 1400)); isn't nice Dimmension, comment this code line, lets that for pack()
for this job (code posted here) I'd be put JScrollPane and buttonPane to the JFrame directly, instead of usage mainPanel(), otherwise post an SSCCE

Stack swing elements from top to bottom

Consider the following figure:
I need to develop a swing GUI the looks like this. I simply named them jLabel's but there a few images and jLabels in it. The default awt background visible is a JPanel and each red background visible is a serperate JPanel. Now I need them to get stacked as shown above. I tried a number of LayoutManagers and still it doesn't work.
The important point here is that the number of red colored divs are not constant. If there is only one red colored div then it must be displayed at the top, not at the center. As far as i know GridBagLayout should work, but it centers the single red colored jpanel available. All the layout managers are centering them but not stacking them from top to bottom.
Even with anchor set to NORTH then the panels will still be centered. You could work around it by adding a dummy panel to fill the remaining space. Personally I'd stay well away from GridBagLayout though.
JFrame frame = new JFrame();
JPanel content = new JPanel();
content.setBorder(BorderFactory.createLineBorder(Color.red));
frame.setContentPane(content);
frame.getContentPane().setLayout(new GridBagLayout());
frame.setSize(400, 300);
for (int i = 0; i < 3; i++) {
JPanel panel = new JPanel();
panel.add(new JLabel("label1"));
panel.add(new JLabel("label2"));
panel.add(new JLabel("label3"));
panel.setBorder(BorderFactory.createLineBorder(Color.red));
GridBagConstraints con = new GridBagConstraints();
con.gridy = i;
con.gridx = 0;
con.anchor = GridBagConstraints.NORTHWEST;
con.ipady = 10;
frame.getContentPane().add(panel, con);
}
// dummy panel to use up the space (force others to top)
frame.getContentPane().add(
new JPanel(),
new GridBagConstraints(0, 3, 1, 1, 1, 1,
GridBagConstraints.NORTHWEST,
GridBagConstraints.VERTICAL, new Insets(0, 0, 0, 0), 0,
0));
frame.setVisible(true);
GroupLayout example (my favourite layout manager).
JFrame frame = new JFrame();
JPanel content = new JPanel();
frame.setContentPane(content);
frame.getContentPane().setLayout(
new BoxLayout(content, BoxLayout.Y_AXIS));
frame.setSize(400, 300);
GroupLayout gLayout = new GroupLayout(content);
content.setLayout(gLayout);
ParallelGroup hGroup = gLayout.createParallelGroup();
gLayout.setHorizontalGroup(hGroup);
SequentialGroup vGroup = gLayout.createSequentialGroup();
gLayout.setVerticalGroup(vGroup);
for (int i = 0; i < 3; i++) {
JPanel panel = new JPanel();
panel.add(new JLabel("label1"));
panel.add(new JLabel("label2"));
panel.add(new JLabel("label3"));
panel.setBorder(BorderFactory.createLineBorder(Color.red));
hGroup.addComponent(panel);
vGroup.addComponent(panel, GroupLayout.PREFERRED_SIZE,
GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE);
vGroup.addGap(10);
}
frame.setVisible(true);
you can use Vertical BoxLayout, for example:
http://www.java-tips.org/java-se-tips/javax.swing/how-to-use-swing-boxlayout.html
nobody tell us that all JComponents must be visible, for example
from code
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class AddComponentsAtRuntime {
private JFrame f;
private JPanel panel;
private JCheckBox checkValidate, checkReValidate, checkRepaint, checkPack;
public AddComponentsAtRuntime() {
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel(new GridLayout(0, 1));
f.add(panel, "Center");
f.add(getCheckBoxPanel(), "South");
f.setLocation(200, 200);
f.pack();
f.setVisible(true);
}
private JPanel getCheckBoxPanel() {
checkValidate = new JCheckBox("validate");
checkValidate.setSelected(false);
checkReValidate = new JCheckBox("revalidate");
checkReValidate.setSelected(false);
checkRepaint = new JCheckBox("repaint");
checkRepaint.setSelected(false);
checkPack = new JCheckBox("pack");
checkPack.setSelected(false);
JButton addComp = new JButton("Add New One");
addComp.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JPanel b = new JPanel(new GridLayout(0, 4));
b.setBackground(Color.red);
b.setBorder(new LineBorder(Color.black, 2));
//b.setPreferredSize(new Dimension(600, 20));
for (int i = 0; i < 4; i++) {
JLabel l = new JLabel("label" + i + 1);
b.add(l);
if (i == 2) {
l.setVisible(false);
}
}
panel.add(b);
makeChange();
System.out.println(" Components Count after Adds :" + panel.getComponentCount());
}
});
JButton removeComp = new JButton("Remove One");
removeComp.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int count = panel.getComponentCount();
if (count > 0) {
panel.remove(0);
}
makeChange();
System.out.println(" Components Count after Removes :" + panel.getComponentCount());
}
});
JPanel panel2 = new JPanel();
panel2.add(checkValidate);
panel2.add(checkReValidate);
panel2.add(checkRepaint);
panel2.add(checkPack);
checkPack.setSelected(true);
panel2.add(addComp);
panel2.add(removeComp);
return panel2;
}
private void makeChange() {
if (checkValidate.isSelected()) {
panel.validate();
}
if (checkReValidate.isSelected()) {
panel.revalidate();
}
if (checkRepaint.isSelected()) {
panel.repaint();
}
if (checkPack.isSelected()) {
f.pack();
}
}
public static void main(String[] args) {
AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
}
}
You should try the MigLayout it is simple yet powerful. Below I tell miglayout to grow elements, and fill all possible space, then after each element I tell it to go to a new line (wrap). You can find examples and tutorial on MigLayout page http://www.miglayout.com/:
import net.miginfocom.swing.MigLayout;
public class PanelLearning extends JPanel {
public PanelLearning() {
setLayout(new MigLayout("", "[grow, fill]", ""));
for (int i = 0; i < 3; i++) {
JPanel panel = new JPanel();
panel.add(new JLabel("label1"));
panel.add(new JLabel("label2"));
panel.add(new JLabel("label3"));
panel.setBorder(BorderFactory.createLineBorder(Color.red));
add(panel, "span, wrap");
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("Login");
frame.setVisible(true);
frame.setContentPane(new PanelLearning());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.pack();
}
}
Make sure GridBagConstraints.anchor = GridBagConstraints.NORTH when you add components to the panel.

Categories

Resources