I have a GUI with one main JPanel
and inside of it multiple rows, each row being another JPanel
. Every row (of type JPanel
) consists of 4 smaller JPanel
s and every panel out of those 4 has a component inside of it. The end result is a grid like interface.
Main panel has a BoxLayout
and panels that are parts of a row have FlowLayout
.
When I update height of some component (from row) using some listener, entire row becomes taller, which works as expected. But what happens is that not only height is changed, but also width of components (inside a row) is changed. I understand that BoxLayout
is trying to layout the components using maxSize
and minSize
that I can set to be the same value and that worked, but then when I resize the window, other rows expand and the row with same minSize
and maxSize
doesn't and the grid structure becomes messed up.
What I want to achieve, is that I update only the height of the row. And when I resize the window, entire row expands, and the structure of grid is still the grid. Here is the Short, Self Contained, Correct (Compilable), Example:
Main
class:
public class Main {
public static void main(String args[]) {
SwingUtilities.invokeLater(() -> {
new MainFrame(450,150);
});
}
}
MainFrame
class:
public class MainFrame extends JFrame{
public MainFrame(int width, int height) {
super("Title");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(width, height);
setVisible(true);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
JScrollPane scrollPane = new JScrollPane(mainPanel);
add(scrollPane);
for(int i=0; i<50; i++) {
JPanel panel1 = new JPanel();
panel1.setLayout(new FlowLayout(FlowLayout.LEFT));
panel1.setBorder(BorderFactory.createMatteBorder(0, 1, 0, 1, Color.black));
panel1.setPreferredSize(new Dimension(70,35));
JPanel panel2 = new JPanel();
panel2.setLayout(new FlowLayout(FlowLayout.LEFT));
panel2.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.black));
panel2.setPreferredSize(new Dimension(70,35));
JPanel panel3 = new JPanel();
panel3.setLayout(new FlowLayout(FlowLayout.LEFT));
panel3.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.black));
panel3.setPreferredSize(new Dimension(70,35));
JTextArea area1 = new JTextArea("hello " + i);
area1.setPreferredSize(new Dimension(70,25));
panel1.add(area1);
JTextArea area2 = new JTextArea("hello " + i);
area2.setPreferredSize(new Dimension(70,25));
panel2.add(area2);
JTextArea area3 = new JTextArea("hello " + i);
area3.setPreferredSize(new Dimension(70,25));
panel3.add(area3);
JPanel row = new JPanel();
row.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.black));
row.setLayout(new BoxLayout(row, BoxLayout.X_AXIS));
row.add(panel1);
row.add(panel2);
row.add(panel3);
JButton button = new JButton("Click me");
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
buttonPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.black));
buttonPanel.setPreferredSize(new Dimension(70,35));
buttonPanel.add(button);
button.addActionListener(event -> {
panel1.setPreferredSize(new Dimension(panel1.getWidth(), panel1.getHeight() + 30));
area1.setPreferredSize(new Dimension(area1.getWidth(), area1.getHeight() + 30));
area1.updateUI();
});
row.add(buttonPanel);
mainPanel.add(row);
}
}
}
If you run this code and press button it will update not only row's height, but also row's width and grid is not aligned well anymore.
You are setting the "preferred size" based on the "size" of the component. The two can be different.
Your code should be something like:
//panel1.setPreferredSize(new Dimension(panel1.getWidth(), panel1.getHeight() + 30));
Dimension d = panel1.getPreferredSize();
panel1.setPreferredSize(new Dimension(d.width, d.height + 30));
Also, you should not be using updateUI()
. That is a method used internally by Swing on a LAF change.
Instead, when you want to invoke the layout manager you invoke revalidate() on the top level component that was changed:
//area1.updateUI();
panel1.revalidate();