Java Swing add/remove jButtons on runtime

37,738

Solution 1

Original Answer Good in general, but done differently in this case

In order to keep track of an arbitrary number of added JButtons, you will need to keep them in a list.

So, after you create a new button, add the listeners to it, and add it to the pane, you then need to save that new button in a list.

That way you can keep track of all of the buttons you have added.

You could also use a Map<String, JButton> that maps a button name to the button.

Example:

private Map<String, JButton> dynamicButtons;

public void addButton(String name) {
    JButton b = new JButton(name);
    b.addActionListener(someAction);
    yourPanel.add(b);
    dynamicButtons.put(name, b);
    yourPanel.invalidate();
}

public void removeButton(String name) {
    Button b = dynamicButtons.remove(name);
    yourPanel.remove(b);
    yourPanel.invalidate();
}

The following is a full class that lets you add and remove buttons dynamically. It's not exactly what you want, but it should get you really close.

Code for your specific case:

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class ExampleFrame extends JFrame {

    private JButton add, remove;
    private JPanel dynamicButtonPane, addRemovePane;

    private boolean waitingForLocationClick;

    public ExampleFrame() {
        super("Dynamic button example");
        waitingForLocationClick = false;
        add = new JButton("Add Button");
        add.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                addButton(JOptionPane
                        .showInputDialog("Name of the new button:"));
            }
        });
        remove = new JButton("Remove Button");
        remove.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                lookingToRemove = true;
            }
        });
        JPanel mainPane = new JPanel(new BorderLayout());
        dynamicButtonPane = new JPanel();
        dynamicButtonPane.setLayout(null);
        dynamicButtonPane.setPreferredSize(new Dimension(300, 300));
        addRemovePane = new JPanel();
        addRemovePane.add(add);
        addRemovePane.add(remove);
        mainPane.add(dynamicButtonPane, BorderLayout.NORTH);
        mainPane.add(addRemovePane, BorderLayout.SOUTH);
        add(mainPane);
        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
        dynamicButtonPane.addMouseListener(pointSelectorListener);
    }

    private JButton buttonToPlace;

    public void addButton(String name) {
        JButton b = new JButton(name);
        b.setActionCommand(name);
        b.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (lookingToRemove) {
                    if (e.getSource() instanceof JButton) {
                        dynamicButtonPane.remove((Component) e.getSource());
                        dynamicButtonPane.validate();
                        dynamicButtonPane.repaint();
                    }
                } else
                    JOptionPane.showMessageDialog(ExampleFrame.this, "This is " + e.getActionCommand());
            }
        });
        waitingForLocationClick = true;
        lookingToRemove = false;
        buttonToPlace = b;
    }

    public void putButtonAtPoint(Point p) {
        System.out.println("Placing a button at: " + p.toString());
        dynamicButtonPane.add(buttonToPlace);
        buttonToPlace.setBounds(new Rectangle(p, buttonToPlace
                .getPreferredSize()));
        dynamicButtonPane.validate();
        buttonToPlace = null;
        waitingForLocationClick = false;
    }

    private boolean lookingToRemove = false;

    private final MouseListener pointSelectorListener = new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent e) {
            if (waitingForLocationClick) {
                putButtonAtPoint(e.getPoint());
            } else {
                System.out.println("Not in waiting state");
            }
        }
    };

    public static void main(String[] args) {
        new ExampleFrame();
    }
}

Solution 2

Absolutely. All of this stuff can be done programatically at any time. Here are a couple of hints to avoid problems and pitfalls:

  • When you add components to any panel, make sure this is done on the Event Dispatch Thread through SwingUtilities.invokeLater(Runnable). Inside the Runnable, you want to add the component to the panel, hook up the listeners, and re-layout the panel.
  • Use SwingUtilities.isEventDispatchThread() to check to see if you are already on the event dispatch thread. If you are, then you can just run the Runnable immediately instead of calling invokeLater.
  • Once you've modified the layout of a panel, be sure to call Component.invalidate() on the panel to make sure it gets laid out again.
  • Maintain your own list of listeners. Overwrite the add and remove methods on the panel to add or remove them from your list and also from all existing buttons. When you add new buttons, add all listeners on the list.

This is a very common task, and it is fully supported by Java. You should be able to get it done without too much trouble.

Share:
37,738
Deepak
Author by

Deepak

Currently employed as a PHP Developer and I have 6 Years of experience in PHP with the framework knowledge on Codeigniter-2. I also worked on Java projects and I have 2 years of experience in Java. I would like to learn good techniques in programming and as I live in So I learn new things everyday. Recently I attempted my own framework called Mercury

Updated on July 09, 2022

Comments

  • Deepak
    Deepak almost 2 years

    My application has a module which allows the user to add jButtons on the jLayeredpane during runtime. I want to add action listeners to this dynamically added contents and also i have to provide access to delete the dynamically added buttons during runtime. Is there any way to do this ?

    private Map<String, JButton> dynamicButtons;
    
    public void addButton(String name) {
        JButton b = new JButton(name);
        b.addActionListener(new java.awt.event.ActionListener() {
    
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });
    
        jLayeredPane2.add(b);
        dynamicButtons.put(name, b);
        jLayeredPane2.invalidate();
    }
    
    public void removeButton(String name) {
        JButton b = dynamicButtons.remove(name);
        jLayeredPane2.remove(b);
        jLayeredPane2.invalidate();
    }