user1277170
user1277170

Reputation: 3227

How to Dynamically Add JButton to JPanel?

In NetBeans, I have used the GUI editor to make a JFrame and I've put a JPanel in the frame. At the moment, I'm trying to make a new button in the panel when the class constructs. This is the code I have, but I can't seem to get it to work. (The first line makes the button, the other lines try to show it.)

this.jPanel2.add(new JButton("Test"),BorderLayout.NORTH);
this.jPanel2.validate();
this.jPanel2.revalidate();
this.jPanel2.repaint();
this.jPanel2.setVisible(true);
this.revalidate();
this.setVisible(true);
this.repaint();

I've been googling all night, but can't seem to get it to work.

Upvotes: 1

Views: 5926

Answers (3)

Chathura Wijesinghe
Chathura Wijesinghe

Reputation: 3349

Create Dynamic JButton with Image and ActionListener - Java Swing

Create JButton dynamically with Image and the ActionListener . You will be able to change the button height , width horizontal gap and vertical gap in one place.

you can find more details from here

enter image description here

Upvotes: 0

Robin
Robin

Reputation: 36601

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 );
          }
        } );
    
      }
    
    }
    

Upvotes: 3

Thirler
Thirler

Reputation: 20760

Some times when you don't see a button it is a layout manager issue (as in you aren't setting the right properties for the layout manager). You can test this by disabling it:

this.jPanel2.setLayoutManager(null);

And setting bounds for the button (JButton.setBounds()).

If the above fixes your problem, then you need to look into the requirements set by the LayoutManager you are using (see also the answer by Robin).

All the calls to validate(), revalidate() and repaint() are not needed to do this.

Upvotes: 3

Related Questions