I have a JFrame
containing a set of JPanels
in a CardLayout
. Each JPanel
has a different size and I want the JFrame
to adapt to the size of the currently displayed JPanel
(not the JPanel
to adapt to the size of the JFrame
).
How can I achieve this?
The general is: if you have a layout problem, always solve it with an appropriate LayoutManager. Never tweak a component's sizing hint to reach your goal.
In this case, it's particularly easy to adjust the CardLayout. By default, it calculates its prefSize to the max of prefSizes of all cards. Simply subclass and implement to return the prefSize (plus insets) of the currently visible card:
public static class MyCardLayout extends CardLayout {
@Override
public Dimension preferredLayoutSize(Container parent) {
Component current = findCurrentComponent(parent);
if (current != null) {
Insets insets = parent.getInsets();
Dimension pref = current.getPreferredSize();
pref.width += insets.left + insets.right;
pref.height += insets.top + insets.bottom;
return pref;
}
return super.preferredLayoutSize(parent);
}
public Component findCurrentComponent(Container parent) {
for (Component comp : parent.getComponents()) {
if (comp.isVisible()) {
return comp;
}
}
return null;
}
}
Using that (borrowing @mKorbel's example), the main method cleanly shrinks down:
private static void createAndShowUI() {
final CardLayout cardLayout = new MyCardLayout();
final JPanel cardHolder = new JPanel(cardLayout);
final JFrame frame = new JFrame("MultiSizedPanels");
JLabel[] labels = {
new JLabel("Small Label", SwingConstants.CENTER),
new JLabel("Medium Label", SwingConstants.CENTER),
new JLabel("Large Label", SwingConstants.CENTER)};
for (int i = 0; i < labels.length; i++) {
int padding = 50 * (i + 1);
Border lineBorder = BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.blue),
BorderFactory.createEmptyBorder(padding, padding, padding, padding));
labels[i].setBorder(lineBorder);
JPanel containerPanel = new JPanel();
containerPanel.add(labels[i]);
cardHolder.add(containerPanel, String.valueOf(i));
}
JButton nextButton = new JButton("Next");
nextButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cardLayout.next(cardHolder);
frame.pack();
}
});
JPanel btnHolder = new JPanel();
btnHolder.add(nextButton);
frame.add(cardHolder, BorderLayout.CENTER);
frame.add(btnHolder, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
Here is the SSCCE.
1) For continuous increase/decrease of size, you should look for some animation API.
or
2) If isn't there any background task with output to the GUI, you can to pause while sizing the JFrame
. In that case, you would delay the increase/decrease by using Thread#sleep(int)
wrapped into Runnable
thread.
3) Notice (not for OP) using Thread#sleep(int)
directly during EDT would be freeze GUI until the delay ended.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.Border;
//based on HFOE http://stackoverflow.com/questions/5414177/change-size-of-jpanel-using-cardlayout/5414770#5414770
public class MultiSizedPanels {
private static void createAndShowUI() {
final CardLayout cardLayout = new CardLayout();
final JPanel cardHolder = new JPanel(cardLayout);
final JFrame frame = new JFrame("MultiSizedPanels");
JLabel[] labels = {
new JLabel("Small Label", SwingConstants.CENTER),
new JLabel("Medium Label", SwingConstants.CENTER),
new JLabel("Large Label", SwingConstants.CENTER)};
for (int i = 0; i < labels.length; i++) {
int padding = 50;
Dimension size = labels[i].getPreferredSize();
size = new Dimension(size.width + 2 * (i + 1) * padding, size.height + 2 * (i + 1) * padding);
labels[i].setPreferredSize(size);
Border lineBorder = BorderFactory.createLineBorder(Color.blue);
labels[i].setBorder(lineBorder);
JPanel containerPanel = new JPanel();
if (i == 1) {
containerPanel.setPreferredSize(new Dimension(300, 200));
containerPanel.add(labels[i], BorderLayout.CENTER);
cardHolder.add(containerPanel, String.valueOf(i));
} else if (i == 2) {
containerPanel.setPreferredSize(new Dimension(600, 400));
containerPanel.add(labels[i], BorderLayout.CENTER);
cardHolder.add(containerPanel, String.valueOf(i));
} else {
containerPanel.setPreferredSize(new Dimension(800, 600));
containerPanel.add(labels[i], BorderLayout.CENTER);
cardHolder.add(containerPanel, String.valueOf(i));
}
}
JButton nextButton = new JButton("Next");
nextButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
cardLayout.next(cardHolder);
Dimension dim = new Dimension();
for (Component comp : cardHolder.getComponents()) {
if (comp.isVisible() == true) {
dim = comp.getPreferredSize();
}
}
frame.setPreferredSize(dim);
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
frame.pack();
}
});
}
});
JPanel btnHolder = new JPanel();
btnHolder.add(nextButton);
frame.add(cardHolder, BorderLayout.CENTER);
frame.add(btnHolder, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocation(150, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With