I have 20 JLabels and all of them have to change their background color when mouse enters and change back to original color when mouse outs.
Do I have to individually bind 2 Event-listeners of MouseEntered and MouseExited with all JLabels separately, or is there any work around so I can make just 2 events kind of monitoring all JLabels?
Like in the image below: there are about 6 JLabels and I want each one to change its background color whenever the mouse enters the scene and change back to original color when the mouse outs.
So, do I have to individually set event listeners on all JLabels, or there can be a single event listener for all JLabels?
You can register all 20 JLabels with the same mouse listener. You would do something like this:
MouseListener m = new MouseAdapter() // create our own mouse listener
{
#Override
public void mouseEntered(MouseEvent e)
{
e.getComponent().setBackground(Color.RED);; // this method changes the colours of all the labels
}
#Override
public void mouseExited(MouseEvent e)
{
e.getComponent().setBackground(Color.GREEN); // this method changes the colours back to normal
}
};
for (JLabel label: labels) // iterate over all the labels
{
label.addMouseListener(m); // give them all our mouse listener
}
Where "labels" is some collection (List, Set, array...) of your JLabels, and changeLabelColours() and changeLabelColoursBack() are two methods that you define to change the colours.
hope this helps!
EDIT: reading your edited question, I think I should point out that this code will cause ALL labels to change colour when ANY of the labels is moused-over. I think that's what you mean.
You don't "make events". You make eventListeners. And yes, you can do just 2 event listeners and bound them to all JLabels.
Or, if you prefer, you can extends Jlabel into MyJlabel, that has the event listener built in, and save yourself from the repeated binding, if it bothers you.
You can use one MouseListener reference.
You should differentiate event sources based on references or on component name.
Here is an example
final JLabel label1 = new JLabel("label1");
label1.setName("label1");
final JLabel label2 = new JLabel("label2");
label2.setName("label2");
final JLabel label3 = new JLabel("label3");
label3.setName("label3");
MouseListener mouseListener = new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
// you can check references
if(e.getSource() == label1) {
System.out.println("exited " + label1.getName());
} else if (e.getSource() == label2) {
System.out.println("exited " + label2.getName());
} else if (e.getSource() == label3) {
System.out.println("exited " + label3.getName());
}
}
#Override
public void mouseEntered(MouseEvent e) {
String name = ((JComponent)e.getSource()).getName();
// or you can check name of component
switch (name) {
case "label1":
case "label2":
case "label3":
System.out.println("entered " + name);
break;
}
}
};
for (JLabel l : Arrays.asList(label1, label2, label3)) {
l.addMouseListener(mouseListener);
}
Note that labels need to be opaque in order to change their bg color.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class CrazyLabels extends JFrame {
public CrazyLabels() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setLayout(new BorderLayout());
JPanel content = new JPanel();
add(content);
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
MouseAdapter listener = new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
JLabel label = (JLabel)e.getSource();
label.setBackground(Color.red);
}
#Override
public void mouseExited(MouseEvent e) {
JLabel label = (JLabel)e.getSource();
label.setBackground(UIManager.getColor("Label.background"));
}
};
for (int i = 0; i < 5; i++) {
JLabel label = new MyLabel(listener);
label.setText("---- label ----");
content.add(label);
}
pack();
setLocationRelativeTo(null);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new CrazyLabels().setVisible(true);
}
});
}
private static class MyLabel extends JLabel {
public MyLabel(MouseListener listener) {
setOpaque(true);
addMouseListener(listener);
}
}
}
In this example a single listener is used to enforce behavior in all labels.
Related
Is it possible to listen for mouse released event on the component on which it was not pressed?
I know that when mouse is released MouseListener.mouseReleased()is invoked on the listeners for that component when mouse press originated even if the cursor is above other component.
How to inform a component or its listeners that the mouse was over it and it was released?
If you add your MouseListener to the container that holds your components of interest, you can find out which component the mouse is over on press or drag. For instance in the code below, I've added my MouseAdapter (a combination MouseListener, MouseMotionListener, and MouseWheelListener) to the containing JPanel, and after getting the location of the mouse event on the container, I call getComponentAt(Point p) on my container to get the child component that the mouse was over:
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class TestMouseRelease extends JPanel {
private String[] panelNames = { "Panel A", "Panel B" };
public TestMouseRelease() {
setLayout(new GridLayout(1, 0));
MouseAdapter mAdapter = new MyMouseAdapter();
addMouseListener(mAdapter);
addMouseMotionListener(mAdapter);
for (String panelName : panelNames) {
JPanel panel = new JPanel();
panel.setName(panelName);
// panel.addMouseListener(mAdapter);
// panel.addMouseMotionListener(mAdapter);
panel.setBorder(BorderFactory.createTitledBorder(panelName));
panel.add(Box.createRigidArea(new Dimension(300, 300)));
add(panel);
}
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
displayInfo(e, "mousePressed");
}
#Override
public void mouseReleased(MouseEvent e) {
displayInfo(e, "mouseReleased");
}
#Override
public void mouseDragged(MouseEvent e) {
displayInfo(e, "mouseDragged");
}
private void displayInfo(MouseEvent e, String info) {
JComponent comp = (JComponent) e.getSource();
Component childComp = comp.getComponentAt(e.getPoint());
if (childComp != null) {
String name = childComp.getName();
System.out.println(name + ": " + info);
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("TestMouseRelease");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new TestMouseRelease());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Yeah, I handled something similar in my project. I use getBounds() on all component in the container and check if they contain the x,y coordinates of your mouse. Below is my code:
Component[] components = jPanel1.getComponents();
for (Component c : components) {
if (c.getBounds().contains(ev.getXOnScreen(), ev.getYOnScreen())) {
System.out.println(c.getClass());
y = ch.getPosY();
x = ch.getPosX();
}
}
I am relatively new to the Java Swing library and I am attempting to write a tic tac toe program with a 3 by 3 grid of JButtons. When a user selects a button, I am changing the background colour of the row and column that contains the selected button to add a highlighted feel (by changing the button.setBackground() of each JButton to a different colour).
However, I am currently having an issue where the new background colour is removed (and changed back to the old background colour) when the mouse is dragged over one of the highlighted buttons.
There appears to be a mouse event that is repainting the button when the mouse enters the button, however I have tried and failed to turn this event off.
I would greatly appreciate any help! If I need to clarify anything please let me know. Thanks
Set the background to NULL if you want to change the button back to it's default:
button.setBackground(inBounds ? new Color(0xFFFF00) : null);
Here is an example I whipped up. You can use it as a reference.
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class GridRollOver extends JFrame implements MouseListener {
private static final long serialVersionUID = -7134685459910610342L;
public JButton[] buttons = new JButton[9];
public GridRollOver() {
this.setLayout(new GridLayout(3, 3));
for (int i = 0; i < 9; i++) {
JButton b = new JButton();
b.setRolloverEnabled(true);
b.addMouseListener(this);
this.add(b);
buttons[i] = b;
}
this.setVisible(true);
this.setSize(500, 500);
this.setLocationRelativeTo(null);
}
public static void main(String[] args) {
new GridRollOver();
}
public void highlightButtons(Point cursor) {
for (int i = 0; i < buttons.length; i++) {
JButton button = buttons[i];
Point buttonLocation = button.getLocationOnScreen();
double west = buttonLocation.getX();
double east = buttonLocation.getX() + button.getWidth();
double north = buttonLocation.getY();
double south = buttonLocation.getY() + button.getHeight();
boolean inRow = cursor.getX() > west && cursor.getX() < east;
boolean inCol = cursor.getY() > north && cursor.getY() < south;
boolean inBounds = inRow || inCol;
button.setBackground(inBounds ? new Color(0xFFFF00) : null);
}
}
#Override
public void mouseEntered(MouseEvent event) {
highlightButtons(event.getLocationOnScreen());
}
#Override
public void mouseExited(MouseEvent e) { }
#Override
public void mouseClicked(MouseEvent e) { }
#Override
public void mousePressed(MouseEvent e) { }
#Override
public void mouseReleased(MouseEvent e) { }
}
In which you can change the color of button when mouse entered on the button when mouse exit it change to it default color by using MouseListener method mouseEntered(MouseEvent e) and mouseExited(MouseEvent e).
package listener;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* This class is used to show when mouse arrow on the button its color change when exited it again on it same color
* #author Ganesh Patel
*
*/
public class ButtonColorChanger implements MouseListener{
JFrame frame;
JButton buttonArray[];
JPanel contentPane;
public ButtonColorChanger() {
JFrame.setDefaultLookAndFeelDecorated(true);
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = createContentPane();
frame.setContentPane(contentPane);
frame.setVisible(true);
frame.pack();
}
/**
* This method is used to create content pane and add 9 button and call the MouseListener on every button
* #return panel content pane of the frame
*/
public JPanel createContentPane() {
JPanel panel = new JPanel(new GridLayout(3,3));
buttonArray = new JButton[9];
//add 9 button on the panel and call MouseListener on every button
for(int i = 0; i<buttonArray.length; i++) {
buttonArray[i] = new JButton(" O ");
buttonArray[i].addMouseListener(this);
panel.add(buttonArray[i]);
}
return panel;
}
#Override
public void mouseClicked(MouseEvent e) {
}
/**
*This method is used for change the color of button when mouse on it.
*/
#Override
public void mouseEntered(MouseEvent e) {
JButton button = (JButton)e.getSource();
button.setBackground(Color.RED);
}
/**
* This method is used to change the color of button when mouse is not on it.
*/
#Override
public void mouseExited(MouseEvent e) {
JButton button = (JButton)e.getSource();
button.setBackground(null);
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
public static void main(String args[]) {
new ButtonColorChanger();
}
}
How to create a border of JPanel, which will be able to handle MouseEvents?
I tried to do something like that:
abstract public class MyBorder extends LineBorder implements MouseListener
But after implementing virtual methods I cannot assign mouseListener to my class. I guess, that I have to assign it into some JComponent.
So, how can I create some sort of border with mouseListener?
A MouseListener must be added to a Component, not a Border. So to use your class the code would need to be something like:
Border border = new MyBorder();
panel.setBorder( border );
panel.addMouseListener( border );
Here is an SSCCE that supports that borders get mouse events on the component to which they are applied.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
class BorderListener {
private void initGui() {
final JPanel gui = new JPanel();
gui.setBackground(Color.green);
gui.setPreferredSize(new Dimension(300,50));
gui.setBorder(new LineBorder(Color.blue, 10));
gui.addMouseListener( new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent me) {
System.out.println(me.getPoint());
}
});
JOptionPane.showMessageDialog(null, gui);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
BorderListener bl = new BorderListener();
bl.initGui();
}
});
}
}
Typical Output
When clicking in the wide border assigned to this panel, you might see output along these lines.
java.awt.Point[x=8,y=3]
java.awt.Point[x=3,y=26]
java.awt.Point[x=1,y=43]
java.awt.Point[x=15,y=6]
java.awt.Point[x=101,y=5]
java.awt.Point[x=220,y=4]
java.awt.Point[x=287,y=5]
java.awt.Point[x=295,y=3]
Press any key to continue . . .
The border is 10px wide, so if (x||y < 10), it is within the line border.
Update
(Comment to camickr, which also applied to my answer)
Yes but then this mouseListener will be added for the whole JPanel. Not only for my Border. Am I wrong?
Just ignore the event if it happens in the non-border area of the panel.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
class BorderListener {
private void initGui() {
final JPanel gui = new JPanel();
gui.setBackground(Color.yellow);
gui.setPreferredSize(new Dimension(300,50));
gui.setBorder(new LineBorder(Color.orange, 15));
gui.addMouseListener( new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent me) {
int w = gui.getWidth();
int h = gui.getHeight();
int x = me.getPoint().x;
int y = me.getPoint().y;
Insets ins = gui.getInsets();
boolean inBorder =
( x<ins.left ||
x>w-ins.right ||
y<ins.top ||
y>h-ins.bottom);
if (inBorder) {
System.out.println(me.getPoint());
} else {
System.out.println("Ignore!");
}
}
});
JOptionPane.showMessageDialog(null, gui);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
BorderListener bl = new BorderListener();
bl.initGui();
}
});
}
}
Output
java.awt.Point[x=168,y=7]
Ignore!
java.awt.Point[x=164,y=41]
java.awt.Point[x=297,y=39]
java.awt.Point[x=297,y=21]
Ignore!
Ignore!
java.awt.Point[x=2,y=21]
Press any key to continue . . .
I have a Swing app with a large panel which is wrapped in a JScrollPane. Users normally move between the panel's subcomponents by tabbing, so when they tab to something out view, I want the scroll pane to autoscroll so the component with input focus is always visible.
I've tried using KeyboardFocusManager to listen for input focus changes, and then calling scrollRectToVisible.
Here's an SSCCE displaying my current strategy (just copy/paste and run!):
import java.awt.KeyboardFocusManager;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
public class FollowFocus {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final int ROWS = 100;
final JPanel content = new JPanel();
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
content.add(new JLabel(
"Thanks for helping out. Use tab to move around."));
for (int i = 0; i < ROWS; i++) {
JTextField field = new JTextField("" + i);
field.setName("field#" + i);
content.add(field);
}
KeyboardFocusManager.getCurrentKeyboardFocusManager()
.addPropertyChangeListener("focusOwner",
new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (!(evt.getNewValue() instanceof JComponent)) {
return;
}
JComponent focused = (JComponent) evt.getNewValue();
if (content.isAncestorOf(focused)) {
System.out.println("Scrolling to " + focused.getName());
focused.scrollRectToVisible(focused.getBounds());
}
}
});
JFrame window = new JFrame("Follow focus");
window.setContentPane(new JScrollPane(content));
window.setSize(200, 200);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
});
}
}
If you run this example, you'll notice it doesn't work very well. It does get the focus change notifications, but the call to scrollRectToVisible doesn't appear to have any effect. In my app (which is too complex to show here), scrollRectToVisible works about half the time when I tab into something outside of the viewport.
Is there an established way to solve this problem? If it makes any difference, the Swing app is built on Netbeans RCP (and most of our customers run Windows).
My comment to the other answer:
scrollRectToVisible on the component itself is the whole point of that
method ;-) It's passed up the hierarchy until a parent doing the
scroll is found
... except when the component itself handles it - as JTextField does: it's implemented to scroll horizontally to make the caret visible. The way out is to call the method on the field's parent.
Edit
just for clarity, the replaced line is
content.scrollRectToVisible(focused.getBounds());
you have to take Rectangle from JPanel and JViewPort too, then compare, for example
notice (against down-voting) for final and nice output required some work for positions in the JViewPort
import java.awt.KeyboardFocusManager;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
//http://stackoverflow.com/questions/8245328/how-do-i-make-jscrollpane-scroll-to-follow-input-focus
public class FollowFocus {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final int ROWS = 100;
final JPanel content = new JPanel();
content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
content.add(new JLabel(
"Thanks for helping out. Use tab to move around."));
for (int i = 0; i < ROWS; i++) {
JTextField field = new JTextField("" + i);
field.setName("field#" + i);
content.add(field);
}
final JScrollPane scroll = new JScrollPane(content);
KeyboardFocusManager.getCurrentKeyboardFocusManager().
addPropertyChangeListener("focusOwner", new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (!(evt.getNewValue() instanceof JComponent)) {
return;
}
JViewport viewport = (JViewport) content.getParent();
JComponent focused = (JComponent) evt.getNewValue();
if (content.isAncestorOf(focused)) {
System.out.println("Scrolling to " + focused.getName());
Rectangle rect = focused.getBounds();
Rectangle r2 = viewport.getVisibleRect();
content.scrollRectToVisible(new Rectangle(rect.x, rect.y, (int) r2.getWidth(), (int) r2.getHeight()));
}
}
});
JFrame window = new JFrame("Follow focus");
window.setContentPane(new JScrollPane(content));
window.setSize(200, 200);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
});
}
}
Here my short summary.
Add this to your Tools class:
public static void addOnEnter(Component c, Consumer<FocusEvent> onEnter) {
FocusListener fl = new FocusListener() {
#Override
public void focusGained(FocusEvent e) {
onEnter.accept(e);
}
#Override
public void focusLost(FocusEvent e) { }
};
c.addFocusListener(fl);
}
public static void scrollToFocus(FocusEvent e) {
((JComponent) e.getComponent().getParent()).scrollRectToVisible(
e.getComponent().getBounds());
}
and use it like this:
Tools.addOnEnter(component, Tools::scrollToFocus);
component can be JTextField, JButton, ...
One major issue in your code is:
focused.scrollRectToVisible(focused.getBounds());
You are calling scrollRectToVisible on the component itself! Presumably a typo.
Make your JScrollPane a final variable and call
scrollPane.getViewport().scrollRectToVisible(focused.getBounds());
Here jtextbox is the component you want to focus and jscrollpane is your scrollpane:
jScrollpane.getVerticalScrollBar().setValue(jtextbox.getLocation().x);
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();
}
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();
}
}
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.