I've done a search of StackOverflow but all of the questions seem to ask the exact opposite of my problem.
I'm writing code that dynamically adds JLabels
to a JPanel
with a GridLayout
, all contained within a JScrollPane
. Here's an SSCCE:
private JFrame frame;
private JPanel panel;
static Test window;
private JScrollPane scrollPane;
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
window = new Test();
window.frame.setVisible(true);
} catch (final Exception e) {
e.printStackTrace();
}
}
});
for (int i = 0; i < 100; i++) {
try {
EventQueue.invokeAndWait (new Runnable() {
@Override
public void run() {
final JLabel label = new JLabel("Test");
label.setSize(160, 40);
label.setHorizontalAlignment(SwingConstants.CENTER);
// Finalise GUI
window.panel.add(label);
window.panel.revalidate();
window.panel.repaint();
try {
Thread.sleep(100);
} catch (final Exception e) {
e.printStackTrace();
}
}
});
} catch (final Exception e) {
e.printStackTrace();
}
}
}
public Test() {
initialize();
}
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 500, 200);
frame.getContentPane().setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new JPanel();
panel.setLayout(new GridLayout(0, 3));
final JPanel outerPanel = new JPanel();
outerPanel.setLayout(new FlowLayout());
outerPanel.add(panel);
scrollPane = new JScrollPane(outerPanel, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setBounds(12, 0, 460, 160);
frame.getContentPane().add(scrollPane);
}
From my understanding, in GridLayouts
, "each component takes all the available space within its cell." Yet here, the JLabels
don't actually take up all the available space in the JPanel
.
I'm not sure where my mistake is. Is it in the GridLayout
or in the surrounding Components
not giving the GridLayout
enough space?
Thanks all.
Your JLabels are taking all available space. It's your JPanel that's small. Test it yourself with a Border:
panel = new JPanel();
panel.setLayout(new GridLayout(0, 3));
// **** add this to see ****
panel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
If you want the labels to fill out the top, then use a different layout for the outer panel. Note changes marked with the // !!
comment:
final JPanel outerPanel = new JPanel();
// !! outerPanel.setLayout(new FlowLayout());
outerPanel.setLayout(new BorderLayout()); // !!
// !! outerPanel.add(panel);
outerPanel.add(panel, BorderLayout.PAGE_START); // !!
Also that Thread.sleep(...)
is dangerous code in a Swing GUI. If you want a delay in adding components, use the best Swing tool for the job: a Swing Timer. For example
final int timerDelay = 100;
final int maxLabelCount = 100;
new Timer(timerDelay, new ActionListener() {
private int labelCount = 0;
@Override
public void actionPerformed(ActionEvent evt) {
if (labelCount < maxLabelCount) {
final JLabel label = new JLabel("Test");
// !! label.setSize(160, 40); // NO!
label.setHorizontalAlignment(SwingConstants.CENTER);
// Finalise GUI
window.panel.add(label);
window.panel.revalidate();
window.panel.repaint();
} else {
// stop this timer
((Timer) evt.getSource()).stop();
}
labelCount++;
}
}).start();