How to dynamically add JLabels to JPanel?
Solution 1
First off, use a layout. Done correctly the layout will place the components like you want. Secondly, when dynamically adding a component to a layout you need to tell the layout to update. Here is an example, it adds a label each time a button is pressed:
public static void main(String[] args) {
final JFrame frame = new JFrame("Test");
frame.setLayout(new GridLayout(0, 1));
frame.add(new JButton(new AbstractAction("Click to add") {
@Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
frame.add(new JLabel("Bla"));
frame.validate();
frame.repaint();
}
});
}
}));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
SwingUtilities.invokeLater(new Runnable() {
@Override public void run() {
frame.setVisible(true);
}
});
}
Solution 2
As said by @AndrewThompson use a correct LayoutManager
, you should not be messing with setBounds
etc.
Here is an example I made (Simply adds a JLabel
to the JPanel
each time the JButton
is clicked):
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Test {
public Test() {
createAndShowUI();
}
private void createAndShowUI() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
initComponents(frame);
frame.setResizable(false);
frame.pack();
frame.setVisible(true);
}
private void initComponents(final JFrame frame) {
final JPanel panel = new JPanel();
JButton button = new JButton("Add label");
button.addActionListener(new ActionListener() {
int count = 1;
@Override
public void actionPerformed(ActionEvent e) {
JLabel _lbl = new JLabel("Label " + count);//make label and assign text in 1 line
panel.add(_lbl);//add label we made
panel.revalidate();
panel.repaint();
frame.pack();//so our frame resizes to compensate for new components
count++;
}
});
frame.add(panel, BorderLayout.CENTER);
frame.add(button, BorderLayout.SOUTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Test();
}
});
}
}
martin
Updated on January 01, 2020Comments
-
martin over 4 years
I'm having a problem with this. I have a JPanel and normally I would create a JLabel like this:
JLabel lblNewLabel = new JLabel("New label"); lblNewLabel.setBounds(0, 0, 135, 14); panel.add(lblNewLabel);
but I want each time I click a button, in that panel to be created a new JLabel with the same size, but with a different height possition. I tried:
panel.add(new JLabel(stringName));
but this way I don't get to set it's bounds. stringName I get from a JTextField.
-
David Kroukamp over 11 yearsSwing components should also be created on EDT, and
setSize
is a real no no use a correctLayoutManager
and callpack()
onJFrame
before setting it visible -
dacwe over 11 years@DavidKroukamp: No need to do it on the EDT before it is realized (in this case
setVisible(true)
) and aboutpack()
this example needed more space to prove the point. -
David Kroukamp over 11 yearsI dont get what you mean? I see no
invokeLater
block which would causeJFrame#setVisible(true);
to be run on EDT? As for the space thats wherepack()
would come in handy after adding the component to resize the JFrame, if thoughsetSize
is a must rather overridegetPrefferedSize()
and return appropriate dimensions