Composing Swing Components: How do I add the ability to add ActionListeners?
I personally don't think you need a custom Swing component. No need for your UI class to extend any Swing class; you aren't likely to provide much custom behavior. (I might concede for a JPanel that composes others.)
I would prefer composition over inheritance. Have a UI class that has Swing data members and give it methods to add and remove Listeners as you need them. You can change the behavior that way without having to rewrite the UI class. It's nothing more than a container.
public class MyUI
{
private Button b = new Button();
public void addButtonListener(ActionListener listener) { this.b.addActionListener(listener); }
}
How to add Swing components in an ActionListener?
When you dynamically add/remove components from a visible GUI then you need to do:
panel.add(...);
panel.revalidate();
panel.repaint();
If you need more help then post your SSCCE that demonstrates the problem.
How to add ActionListener to customize component
If you really can't use a JButton
for this, your next best option is extending AbstractButton
, which includes the EventListenerList
plumbing mentioned here. For example,
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.DefaultButtonModel;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.plaf.ButtonUI;
/** @see https://stackoverflow.com/a/14429304/230513 */
public class JCButtonTest {
private void display() {
JFrame f = new JFrame("JCButtonTest");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new JCButton(new AbstractAction("JCButton") {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e);
}
}));
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class JCButton extends AbstractButton {
public static final int SIZE = 32;
public JCButton(Action action) {
this.setModel(new DefaultButtonModel());
System.out.println(action.getValue(Action.NAME));
this.init((String) action.getValue(Action.NAME), null);
this.addActionListener(action);
}
@Override
public void updateUI() {
setUI((ButtonUI) UIManager.getUI(this));
}
@Override
public String getUIClassID() {
return "ButtonUI";
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new JCButtonTest().display();
}
});
}
}
How to add an ActionListener while adding an Instantiation of a JComponent to a JContainer?
Three Options:
Option 1: In my opinion the cleanest
JFrame frame = new JFrame();
JButton button = new JButton("Click Here");
frame.add(button);
button.addActionListener(this);
Option 2 Anonymous class
JFrame frame = new JFrame();
JButton button = new JButton("Click Here");
frame.add(button);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Clicked");
}
});
Option 3
This is not recommended, ugly and has unintended side effects (imagine calling add again). But you asked for a way to do it directly inside the add.
JFrame frame = new JFrame();
JButton button = new JButton("Click Here");
frame.add(new JButton("Click Here"){
@Override
public void addActionListener(ActionListener l) {
super.addActionListener(YourClass.this);
}
});
Java Swing; Two classes, where to put if statements and new actionlisteners?
Because ClockListener
is a nested class (lower), the enclosing instance (upper) can access the listener's private fields. If you have a reference to an instance of ClockListener
,
ClockListener cl = new ClockListener();
you can use it to initialize your timer
Timer t = new Timer(1000, cl);
and you can use it in your test:
if (cl.count == 2) { t.stop(); }
Addendum: For reference, here's a variation of your program that uses a JToggleButton
to control the timer. As suggested earlier, you had used Calendar
to minimize Timer
drift. Like you, I abandoned the approach as irrelevant in a low-resolution application.
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.Timer;
/** @see https://stackoverflow.com/questions/5528939*/
class ClockExample extends JFrame {
private static final int N = 60;
private static final String stop = "Stop";
private static final String start = "Start";
private final ClockListener cl = new ClockListener();
private final Timer t = new Timer(1000, cl);
private final JTextField tf = new JTextField(3);
public ClockExample() {
t.setInitialDelay(0);
JPanel panel = new JPanel();
tf.setHorizontalAlignment(JTextField.RIGHT);
tf.setEditable(false);
panel.add(tf);
final JToggleButton b = new JToggleButton(stop);
b.addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (b.isSelected()) {
t.stop();
b.setText(start);
} else {
t.start();
b.setText(stop);
}
}
});
panel.add(b);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.add(panel);
this.setTitle("Timer");
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void start() {
t.start();
}
private class ClockListener implements ActionListener {
private int count;
@Override
public void actionPerformed(ActionEvent e) {
count %= N;
tf.setText(String.valueOf(count));
count++;
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
ClockExample clock = new ClockExample();
clock.start();
}
});
}
}
Related Topics
Java Web Start Support in Java 9 and Beyond
How to Handle Precision Error with Float in Java
How Does Java's Preparedstatement Work
Dragging a Jlabel Around the Screen
Wrap the String After a Number of Characters Word-Wise in Java
Populate Jtable with Large Number of Rows
How to Compile a .Java with Support for Older Versions of Java
Are Java Primitive Ints Atomic by Design or by Accident
How to Output Two Columns to the Console in Java
Simpledateformat Parse(String Str) Doesn't Throw an Exception When Str = 2011/12/12Aaaaaaaaa
Refreshing Gui by Another Thread in Java (Swing)
How to Draw an Image Over Another Image
Arrayindexoutofboundsexception When Iterating Through All the Elements of an Array