Normally the add
call is sufficient.
Note: a BorderLayout
can only contain one component in each location. So if you add another component in the NORTH
location, your button will not be visible.
Second note: by default a JPanel
does not have a BorderLayout
but a FlowLayout
. Have you set a BorderLayout
on that specific panel ? Otherwise the BorderLayout#NORTH
constraint is incorrect
All the validate
,revalidate
,repaint
calls can be removed
Edit
It seems some sort of validation is needed after all. I was under the impression that Swing should be smart enough to listen for the event when something is added to a Container
, and update whatever is necessary (a bit similar to updating a TableModel
updates the JTable
based on events, without the need to call repaint
or the likes on the JTable
).
However, when trying this in an SSCCE, I came to the following code (different versions, only post the most elaborate version)
- without the scroll-pane, the
validate
calls seem to have no effect. I actually need to call pack
again to make the new labels visible (not included in the SSCCE, but removing the scrollpane from the code is trivial)
with the scroll-pane, the validate
call has an effect
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AddLabelsAtRuntime {
private int fLabelCounter = 0;
private JPanel fLabelPanel;
private final JFrame fTestFrame;
public AddLabelsAtRuntime() {
fLabelPanel = new JPanel( );
BoxLayout boxLayout = new BoxLayout( fLabelPanel, BoxLayout.PAGE_AXIS );
fLabelPanel.setLayout( boxLayout );
fTestFrame = new JFrame( "Dynamically add labels" );
}
private JFrame createUI(){
Container contentPane = fTestFrame.getContentPane();
contentPane.setLayout( new BorderLayout() );
JScrollPane scrollPane = new JScrollPane( fLabelPanel );
scrollPane.setPreferredSize( new Dimension( 200, 200 ) );
contentPane.add( scrollPane, BorderLayout.CENTER );
contentPane.add( createButtonPanel(), BorderLayout.SOUTH );
fTestFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
fTestFrame.pack();
return fTestFrame;
}
private void addLabel(){
fLabelPanel.add( new JLabel( "Label " + ++fLabelCounter ) );
}
private JPanel createButtonPanel(){
JPanel buttonPanel = new JPanel( );
BoxLayout boxLayout = new BoxLayout( buttonPanel, BoxLayout.LINE_AXIS );
buttonPanel.setLayout( boxLayout );
JButton validateButton = new JButton( "Add + validate" );
validateButton.addActionListener( new ActionListener() {
@Override
public void actionPerformed( ActionEvent e ) {
addLabel();
fLabelPanel.validate();
fTestFrame.validate();
}
} );
buttonPanel.add( validateButton );
JButton noValidateButton = new JButton( "Add" );
noValidateButton.addActionListener( new ActionListener() {
@Override
public void actionPerformed( ActionEvent e ) {
addLabel();
}
} );
buttonPanel.add( noValidateButton );
JButton packButton = new JButton( "Add + pack" );
packButton.addActionListener( new ActionListener() {
@Override
public void actionPerformed( ActionEvent e ) {
addLabel();
fTestFrame.pack();
}
} );
buttonPanel.add( packButton );
return buttonPanel;
}
public static void main( String[] args ) {
EventQueue.invokeLater( new Runnable() {
@Override
public void run() {
AddLabelsAtRuntime addLabelsAtRuntime = new AddLabelsAtRuntime();
addLabelsAtRuntime.createUI().setVisible( true );
}
} );
}
}