How can set location and size for card layout? - java

I've been working on this small trivia game as a project to keep me busy, but I can't figure out how to make it look good. preferably, the buttons would be at the top and the question would be towards the bottom with a set window size. Although setSize() or setPreferredSize() aren't working. So the window is very thin and the buttons and question are all at the top.
package mainPackage;
import javax.swing.JFrame;
public class MainGame{
public static void main(String[] args) {
new WindowComp();
}
}
package mainPackage;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class WindowComp extends JComponent implements ActionListener {
JFrame frame = new JFrame("trivia game");
static JButton [] buttons;
static JLabel question;
JPanel panelCont = new JPanel();
JPanel panelStartScreen= new JPanel();
JPanel panelGame = new JPanel();
JButton startGame = new JButton("Start Trivia");
CardLayout cl = new CardLayout();
public WindowComp(){
question = new JLabel("default");
buttons = new JButton[4];
panelCont.setLayout(cl);
buttons[0] = new JButton("Answer 1 : " + "default");
buttons[1] = new JButton("Answer 2 : " + "default");
buttons[2] = new JButton("Answer 3 : " + "default");
buttons[3] = new JButton("Answer 4 : " + "default");
buttons[0].addActionListener(this);
buttons[1].addActionListener(this);
buttons[2].addActionListener(this);
buttons[3].addActionListener(this);
startGame.addActionListener(this);
addAll();
panelCont.add(panelStartScreen, "1");
panelCont.add(panelGame, "2");
frame.add(panelCont);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(300, 300);
frame.pack();
frame.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == buttons[0]){
setQuestion("button 1");
setAnswers( "start", "start", "start", "start");
}
if(e.getSource() == buttons[1]){
setQuestion("button 2");
setAnswers("final", "final", "final", "final");
}
if(e.getSource() == buttons[2]){
setQuestion("button 3");
}
if(e.getSource() == buttons[3]){
setQuestion("button 4");
}
if(e.getSource()==startGame){
cl.show(panelCont, "2");
}
}
public void addAll(){
panelGame.add(buttons[0]);
panelGame.add(buttons[1]);
panelGame.add(buttons[2]);
panelGame.add(buttons[3]);
panelGame.add(question);
panelStartScreen.add(startGame);
}
public static void setAnswers( String ans1, String ans2, String ans3,String ans4){
buttons[0].setText("Answer 1 : " + ans1);
buttons[1].setText("Answer 2 : " + ans2);
buttons[2].setText("Answer 3 : " + ans3);
buttons[3].setText("Answer 4 : " + ans4);
}
public static void setQuestion(String q){
question.setText("Question: " + q);
}
}

Things to note:
1. Calling JFrame.pack() rearranges its components and resizes the JFrame.
2. It's easier (I find) to make a JPanel, call JPanel.setPreferredSize(new Dimension(width, height)), place components inside it, and add it to the JFrame. That way, you may still call JFrame.pack() and the JPanel stays its preferred size.
3. You can remove JFrame.pack(), call JFrame.setPreferredSize(new Dimension(width, height)), and/or JFrame.setResizable(false).
4. You can call JFrame.setMinimumSize(new Dimension(width, height)) to keep it from packing too tightly. Note that this method will not guarantee the specified dimensions when you call JFrame.pack(). In your case, the width stretches a bit due to JFrame.pack() being called afterwards.
5. For your program, I recommend you use JFrame.setLayout(new BorderLayout()), and make a JPanel with a FlowLayout/GridLayout and add your buttons. Then place the JPanel on the BorderLayout.NORTH area. Then create another JPanel, place your questions inside it using a layout of your choice, and add it to BorderLayout.CENTER area in the JFrame. After noting the minimum size that does not interfere with component visibility, configure JFrame.setMinimumSize(new Dimension(width, height)).
6. Layout managers get rid of all the headaches involved with component placements after resizing a window, but rare instances do exist where using setLayout(null) is the best option (see Fig1). If you don't care about users' ability to resize your app, calling JFrame.setResizable(false) will suffice. This will give rise to compatibility issues with lower resolution displays, however.
Figure 1. Placing buttons in this fashion required me to abandon layout managers and configure placement of these buttons according to the width and height variables that update upon resizing the window.
Good luck!

Related

CardLayout - How to Delete current card (Java Swing)

How would one delete the current card that the user is on. I know how to go through a card layout using the next and previous function, but how would one remove the current frame that the user is on? For example, if I have a program where I am currently on the 3rd panel out of 5 total panels, how would I delete the current one which is the 3rd panel. Once you remove it, the next or previous one replaces it. I do not think removecurrentlayout can be used cause I am not removing a component. For example, in the code, how would I go about delete Card 3 if I am on that.
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Container;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class CardLayoutProg {
public static void main(String[] args) {
JFrame frame = new JFrame("CardLayout");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container contentPane = frame.getContentPane();
JPanel buttonPanel = new JPanel();
JButton nextButton = new JButton("Next");
buttonPanel.add(nextButton);
contentPane.add(buttonPanel, BorderLayout.SOUTH);
final JPanel cardPanel = new JPanel();
final CardLayout cardLayout = new CardLayout();
cardPanel.setLayout(cardLayout);
for (int i = 1; i <= 5; i++) {
JButton card = new JButton("Card " + i);
card.setPreferredSize(new Dimension(200, 200));
String cardName = "card" + 123123;
cardPanel.add(card, cardName);
}
contentPane.add(cardPanel, BorderLayout.CENTER);
nextButton.addActionListener(e -> cardLayout.next(cardPanel));
frame.pack();
frame.setVisible(true);
}
}
If you look at the docs for Container, you will see that it has a remove() method. Since JPanel extends Container, it also has this method. You should familiarize yourself with these API docs to find this kind of information.
Unfortunately the CardLayout does not tell you which card (JPanel) is currently being displayed.
Check out Card Layout Focus for a class that extends the CardLayout to provide this functionality.
You would use the getCurrentCard() method to access the panel currently being displayed.
Then once you get the card currently being displayed you can remove it from the parent panel using by the remove(...) method of the Container class.
You would just use the class as follows:
//final CardLayout cardLayout = new CardLayout();
final RXCardLayout cardLayout = new RXCardLayout();
The logic for your "Remove" button would be:
cardPanel.remove(cardLayout.getCurrentCard());
When you say index(3rd panel of 5 panels), you mean the name (String) of the component when it was inserted, right? I don't know any elegant way to do this, but you can try to get all the components in this container (parentComponent) and try to find the one that has the same name as your index. For example:
Component[] components = parentComponent.getComponents();
for(int i = 0; i < components.length; i++) {
if(components[i].getName().equals(index)) {
cardLayout.removeLayoutComponent(components[i]);
}
}

how would i change my code to cardLayout

package garage;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
*
* #author Jela
*/
public class VehicleParts extends JPanel {
public VehicleParts() {
JPanel card0 = new JPanel();
//card0.setPreferredSize(new Dimension(800, 600));
JPanel card1 = new JPanel(new BorderLayout());
JPanel card2 = new JPanel(new BorderLayout());
JPanel card3 = new JPanel(new BorderLayout());
JLabel zero = new JLabel("0");
JLabel one = new JLabel("1");
JLabel two = new JLabel("2");
JLabel three = new JLabel("3");
card0.add(zero);
card1.add(one);
card2.add(two);
card3.add(three);
card1.setVisible(false);
card2.setVisible(false);
card3.setVisible(false);
card0.setVisible(false);
JButton buttonZero = new JButton("Repair");
JButton buttonOne = new JButton("Parts");
JButton buttonTwo = new JButton("Stock");
JButton buttonThree = new JButton("Supplier");
//JButton buttonback = new JButton("Parts");
buttonZero.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
card0.setVisible(true);
card1.setVisible(false);// shows card1 when button is clicked
card2.setVisible(false);
card3.setVisible(false);
}
});
buttonOne.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
card1.setVisible(true);// shows card1 when button is clicked
card2.setVisible(false);
card3.setVisible(false);
card0.setVisible(false);
}
});
add(buttonZero);
add(buttonOne);
add(buttonTwo);
add(buttonThree);
add(card0);
add(card1);
add(card2);
add(card3);
}
}
Im not sure how i would change this code into CardLayout. If anyone can give me tips of how i could change it, please tell me. This is not my main class. Ive tried cardlayout, however whenever i use it, i cannot see my buttons anymore.
To make sure the buttons are visible using all the cards, you simply divide the panel into two panels - one panel that will contain the buttons, and the other that will contain the cards.
So - your main panel (VehicleParts) will have a BorderLayout.
You add two panels to it. One is the cards panel. It will have a CardLayout. Make the cards panel reference variable final, so that you can access it from the buttons' event listeners (which are anonymous classes). Although the cards panel itself has a card layout, you add it to your main panel using BorderLayout.CENTER.
The other panel is the buttons panel. It can have a GridLayout, for example. Add it to the main panel using, perhaps, BorderLayout.SOUTH to put it at the bottom.
Add your cards to the cards panel. Don't forget to give them names.
Then create the buttons, and in each button's listener, change cards using the CardLayout.show() method. Add each button to the buttons panel.

Last button in JFrame is set as background?

import javax.swing.JButton;
import javax.swing.JFrame;
public class Test extends JFrame {
private static final long serialVersionUID = 1L;
public Test() {
super("A test");
setSize(360,300);//Size of JFrame
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);//Sets if its visible.
JButton num1 = new JButton("1");//Set the JButton name
JButton num2 = new JButton("2");
JButton num3 = new JButton("3");
num1.setBounds(80,70,50,50);
num2.setBounds(130,70,50,50);
num3.setBounds(180,70,50,50);
add(num1);
add(num2);
add(num3);
}
public static void main (String[] args) {
new Test().setVisible(true);
}
}
Here the num3 button is set as the background, I want the buttons to be aligned. This might be a trivial mistake I'm not sure as I've just started working with JFrame. Thank you.
The Problem
Basically, there are three parts that are causing this problems...
JFrame uses a BorderLayout by default. This means that only the last component add to any one of the five available layout positions will be managed
You call setVisible(true) before adding anything to the frame
You call setBounds on the buttons.
Because the components are generally painted in z-order (in FIFO order generally) and because of the optimisation in the code, the last button is been controlled by the BorderLayout of the frame, but the other two maintain the bounds you set before
Really interesting problem
Solution(s)
Use an appropriate layout manager, maybe a FlowLayout or GridBagLayout
Call setVisible last where ever possible
Check out Laying Out Components Within a Container for details
This is because of Layout Manager. Please check the code below.
i use another JPanel to put all the buttons. i set the panel as it will have 1 row and 3 columns objects.
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Test extends JFrame {
private static final long serialVersionUID = 1L;
JPanel buttonPanel;
public Test() {
super("A test");
setSize(360,300);//Size of JFrame
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);//Sets if its visible.
setLayout(null);
buttonPanel = new JPanel(new GridLayout(1, 3));
buttonPanel.setBounds(80, 70, 150, 50);
JButton num1 = new JButton("1");//Set the JButton name
JButton num2 = new JButton("2");
JButton num3 = new JButton("3");
buttonPanel.add(num1);
buttonPanel.add(num2);
buttonPanel.add(num3);
add(buttonPanel);
}
public static void main (String[] args) {
new Test().setVisible(true);
}
}
Well, never use raw placing and no Layout Manager.
This is your Bible
You can do that with some Layout tricks. For example this one:
First of all import the Layout classes.
import java.awt.GridLayout;
import java.awt.BorderLayout;
Make the frame a BorderLayout frame by copying this in the constructor of it.
setLayout(new BorderLayout());
Then make another JPanel and make it a GridLayout JPanel:
JPanel panel = new JPanel(new GridLayout(1,3));
panel.add(num1);
panel.add(num2);
panel.add(num3);
Arguments 1 and 3 mean "use exactly 1 row and 3 columns to place the widgets in this JPanel".
Finally add the last panel at the center of the frame:
add(panel,BorderLayout.CENTER);
This way you won't deal with dimensions or precise spots and still do what you want...
(to test it copy all the code in "Test" constructor)

JFrame Screen Replacing Questions

The problem that I am having is when I try to replace the main screen with a second one and it deletes the old one but is stuck placing in the new one. If I maximize the screen I can see the new Panels. Another question I had was how to take up spaces in a grid layout without using all of the filler jpanels that I have to do. The code is below:
package home.personalprojects.jordan.ArrayGame;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class GuiMain extends JFrame
{
private JButton Inventory, Store, Up, Down, Left, Right, Move, GameInfo, Back = new JButton("Back");
private JLabel pstats, roominfo;
private JPanel Filler1,Filler2,Filler3,Filler4,Filler5,Filler6,Filler7,Filler8,Filler9,Filler10,Filler11;
private JPanel Controls, Main = new JPanel(), BackPanel;
PlayerTraits pt = new PlayerTraits();
Rooms rm = new Rooms();
public GuiMain(){
super("Dungeon Crawler v 0.0.1 Created By: Jordan Savage");
Main.setLayout(new GridLayout(4,3));
//mainbuttons
Inventory = new JButton("Inventory");
Inventory.setToolTipText("Gives you access to all of your items and lets you manage them");
Store = new JButton("Store");
Store.setToolTipText("The marketplace where you can buy and sell items such as swords and armor");
Move = new JButton("Move");
Move.setToolTipText("Choose where you want to move next");
GameInfo = new JButton("Game Information and Settings");
GameInfo.setToolTipText("All the info for the game including instructions, version info, and settings");
//main labels
pstats = new JLabel(pt.name + ": " + pt.gold + " Gold, " + pt.health + " Health, and Level is " + pt.lvl);
roominfo = new JLabel("You are at: (" + pt.x + "," + pt.y + ") In room: " + rm.name);
//fillers for grid layout
Filler1 = new JPanel();Filler2 = new JPanel();Filler3 = new JPanel();Filler4 = new JPanel();Filler5 = new JPanel();Filler6 = new JPanel();Filler7 = new JPanel();Filler7 = new JPanel();Filler8 = new JPanel();Filler9 = new JPanel();Filler10 = new JPanel();Filler11 = new JPanel();
//action listeners
Move.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
ControlScheme();
BackToMain();
getContentPane().removeAll();
getContentPane().add(Controls, BorderLayout.CENTER);
getContentPane().add(BackPanel, BorderLayout.SOUTH);
getContentPane().doLayout();
update(getGraphics());
}
});
Back.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
getContentPane().removeAll();
getContentPane().add(Main);
getContentPane().doLayout();
update(getGraphics());
}
});
Main.add(Inventory);
Main.add(Filler1);
Main.add(Store);
Main.add(Filler2);
Main.add(pstats);
Main.add(Filler3);
Main.add(Filler4);
Main.add(roominfo);
Main.add(Filler5);
Main.add(Move);
Main.add(Filler6);
Main.add(GameInfo);
add(Main);
}
public void BackToMain(){
BackPanel = new JPanel();
BackPanel.setLayout(new FlowLayout());
BackPanel.add(Back);
}
public void ControlScheme(){
Up = new JButton("Up");
Down = new JButton("Down");
Left = new JButton("Left");
Right = new JButton("Right");
Controls = new JPanel();
Controls.setLayout(new GridLayout(3,3));
Controls.add(Filler7);
Controls.add(Up);
Controls.add(Filler8);
Controls.add(Left);
Controls.add(Filler9);
Controls.add(Right);
Controls.add(Filler10);
Controls.add(Down);
Controls.add(Filler11);
}
public static void main(String[] args)
{
GuiMain gm = new GuiMain();
gm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gm.setSize(800, 600);
gm.setVisible(true);
gm.setLocationRelativeTo(null);
}
}
Any Help Is Appreciated :)
The short answer would be to call revalidate on the frame.
The better answer would be to use a CardLayout, which was designed to do exactly what you are trying to do...
As to your second question, it can't be done with GridLayout, in fact, you might find it difficult to achieve even with GridBagLayout which gives you control over the placement of components within the virtual grid.
What you might be able to do, is use the fill the grid with empty panels, keeping them in some kind of matrix lookup (ie getComponentAt(gridx, gridy)) and use these to place your components onto instead.
So, for example. If you wanted to place a panel at grid 2x3, you would simply look at the panel at that grid location and place your components onto it.
ps- While I think about, you might also need repaint after revalidate if revalidate along doesn't work...

Java Swing recursive layout

I know this might seem like a duplicate, but I'm not getting anywhere with by experimenting on invalidate/validate/revalidate/repaint, so please bear with me. My panel structure looks something like this:
JPanel/GridBagLayout (1)
+-- JPanel/BorderLayout
+-- JPanel/GridBagLayout (2)
| +-- JTextField (3)
| +-- JComboBox
+-- JPanel/WhateverLayout
...
... and so forth. In my sub panel (2) I change the insets (right and bottom), and I want to layout the whole top panel (1). Is there some easy way to layout everything (preferably from top panel (1) and down, but anything that works is okey). Right now I've tried combinations of invalidate/validate/revalidate/repaint on all levels, but nothing seems to work (in fact nothing changes at all). Thanks!
Edit: I found out that GridBagLayout clones the GridBagConstraints as components are added, so the reason my code didn't work by running revalidate and friends was that I updated the wrong constraints. I found and added a solution to this problem below.
for re_layout whole JFrame(JDialog e.i.) is there JFrame#pack()
for fill available area in the container (after remove / add) is there revalidate() and repaint()
you have to decide for which of containers in the Components hierarchy
code example about pack() & (re)validate() & repaint()
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class AddComponentsAtRuntime {
private JFrame f;
private JPanel panel;
private JCheckBox checkValidate, checkReValidate, checkRepaint, checkPack;
public AddComponentsAtRuntime() {
JButton b = new JButton();
b.setBackground(Color.red);
b.setBorder(new LineBorder(Color.black, 2));
b.setPreferredSize(new Dimension(600, 10));
panel = new JPanel(new GridLayout(0, 1));
panel.add(b);
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
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) {
JButton b = new JButton();
b.setBackground(Color.red);
b.setBorder(new LineBorder(Color.black, 2));
b.setPreferredSize(new Dimension(600, 10));
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);
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) {
EventQueue.invokeLater(new Runnable() {
public void run() {
AddComponentsAtRuntime makingChanges = new AddComponentsAtRuntime();
}
});
}
}
GridBagLayout clones the GridBagConstraints as components are added (that's why changing my original once had no effect on the layout), so I extended GridBagLayout to be able to update the actual constraints runtime. The code below sets the layout margins depending on type of component, and if "expanded", which is what I use to toggle between two modes:
public class ExpandableGridBagLayout extends GridBagLayout {
public void setExpand(boolean expanded) {
for (Map.Entry<Component, GridBagConstraints> entry : comptable.entrySet()) {
setExpandedMargin(entry.getKey(), entry.getValue(), expanded);
}
}
private void setExpandedMargin(Component component, GridBagConstraints constraints, boolean expanded) {
constraints.insets.right = 2;
if (component instanceof JLabel) {
constraints.insets.top = expanded ? 3 : 0;
constraints.insets.bottom = expanded ? 3 : 0;
} else {
constraints.insets.bottom = expanded ? 8 : 5;
}
}
}
Then all I had to do was to call panel.revalidate() on (1) and layouting works as expected.
Still not entirely sure about your exact context, but judging from your "answer" you seem to be changing component constraints on the fly. To trigger a re-layout of the effected parts, you need to
invalidate the child/ren whose constraints had been changed (note: it's not enough to invalidate the parent), this will bubble up the hierarchy as needed
validate an appropriate container up the hierarchy
Snippet:
ExpandableGridBagLayout bag = panel2.getLayout();
bag.setExpand(true);
for(Component child: panel2.getComponents())
child.invalidate();
panel1.validate();
There is no public api to recursively invalidate everything below a given container (invalidateTree is package private). A quick hack is to temporarily toggle the font of the parent container (which internally messages invalidateTree)
/**
* Invalidates the component hierarchy below the given container.<p>
*
* This implementation hacks around package private scope of invalidateTree by
* exploiting the implementation detail that the method is internally
* used by setFont, so we temporary change the font of the given container to trigger
* its internal call.<p>
*
* #param parent
*/
protected void invalidateTree(Container parent) {
Font font = parent.getFont();
parent.setFont(null);
parent.setFont(font);
}
EDIT
Don't know which part of this answer you exactly mean by incorrect - obviously I couldn't solve your problem without any detailed knowledge about it ;-)
Curious me is wondering how a revalidate up in the hierarchy would lead to a re-layout of valid grand/children: validate/Tree clearly stops at a valid component. Below is a code-snippet to play with
it's a two-level hierarchy, a parent with two children
the action changes layout-effecting properties of the sister under its feet (we change v/hgap of the layout) and revalidate the parent
The outcome varies, depending f.i. on the LayoutManager of the parent
with FlowLayout nothing happens ever,
with BoxLayout it may be validated, depending on
whether the horizontal or vertical gap was changed and
the direction of the Box
Looks like a relayout of a valid child might be (or not) a side-effect of a relayout higher up - without any guarantee to happen and hard to predict. Nothing I want to rely on ;-)
final JComponent sister = new JPanel();
final Border subBorder = BorderFactory.createLineBorder(Color.RED);
sister.setBorder(subBorder);
sister.add(new JTextField(20));
sister.add(new JButton("dummy - do nothing"));
JComponent brother = new JPanel();
brother.setBorder(BorderFactory.createLineBorder(Color.GREEN));
brother.add(new JTextField(20));
// vary the parent's LayoutManager
final JComponent parent = Box.createVerticalBox();
// final JComponent parent = Box.createHorizontalBox();
// final JComponent parent = new JPanel();
parent.add(sister);
parent.add(brother);
// action to simulate a change of child constraints
Action action = new AbstractAction("change sub constraints") {
#Override
public void actionPerformed(ActionEvent e) {
FlowLayout layout = (FlowLayout) sister.getLayout();
layout.setHgap(layout.getHgap() * 2);
// layout.setVgap(layout.getVgap() * 2);
// sister.invalidate();
parent.revalidate();
}
};
brother.add(new JButton(action));
JFrame frame = new JFrame("play with validation");
frame.add(parent);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);

Categories