views:

64

answers:

2

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();
}
+2  A: 

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();
    }
}
jjnguy
i am new to swing so can u elaborate little bit ? I will appreciate if you explain with code sample..
Deepak
@Deepak, you need 2 static buttons in your Frame. One for adding a button, and one for removing a button. You will then add an action listener to both of those buttons. The action for the Add button will be the `addButton(string)` method, and the action for the Remove button will be `removeButton(string)`.
jjnguy
thanks for the code explanation, just tell me where should i add this bit of code ? is it in a separate class file or along with the jframe file ?
Deepak
@Deepak, This will go in your `JFrame`.
jjnguy
and tel me incase if i call removeButton(string), "string" is the name of the button in our context. Now how i want to design my application is that when user clicks on jLayeredpane it adds a button on the clicked atea which i am doing it with moues co-ordinates. Now if i set delete flag and call removeButton(string), i want to allow the user to remove the button same as the way they created it (by clicking on the created button)
Deepak
@Deepak, that is something that I do not know off the top of my head unfortunately. You will have to use a mouse listener and find the component that originated the event (your button to remove) and remove it that way.
jjnguy
I will try that and let me kno if you remmeber anything. And thanks a lot for your replies!!!
Deepak
in your code you have given "b.addActionListener(someAction);" wat do i need to give in that someAction ? where do i create that action ?
Deepak
@Deepak, that action is whatever you want that button to do.
jjnguy
@Deepak, check out the class I posted. I think it is semi-close to what you need.
jjnguy
yes i will try that template. thanks a lot for posting..
Deepak
is this the code for adding actionlistner for dynamically added buttons ?
Deepak
@Deepak, see my latest edit. I added modified the class to do exactly what you need, I think.
jjnguy
@Deepak, the code for adding the action listener to a dynamically created button is in the `addButton(String name)` method.
jjnguy
I managed to do the remove button script as well. The code i used is exactly the same as the one you have given but insted of e.getSource() i user e.getActionComand()
Deepak
@Deepak, glad you could get this to work out.
jjnguy
you are awesome man!!! can u get me some information regarding my query on http://stackoverflow.com/questions/3475414/jbuttons-resize-on-runtime
Deepak
@Deepak, I will look into it. I have less time today than I did yesterday unfortunately. `:(`
jjnguy
@Deepak, that was actually a fun problem to solve.
jjnguy
A: 

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.

Erick Robertson
I know we can do this but i am new to swing concepts so i dunno much abt it. I have one more issue i need to give different names to buttons created. can u explain it in code sample ? or just gimme a link to follow. I want the code sample for my original question aswell.
Deepak
You asked if there was any way to do this, and there is. The code sample would be quite implementation dependent. As you are the one implementing it, you should have no problem putting together the code to do it and figuring out the details. If you get stuck with a particular detail, ask about that specifically.
Erick Robertson
Basically, there are a lot of things going on. You asked a pretty high-level question with several moving parts in the answer. It's way too much code to write out just for one question. I highly recommend you try it yourself and ask another question if you get stuck with something.
Erick Robertson