Understanding ActionListener - java

I just started getting my head around Java itself and Java Swing and I have some problems understanding the "Action Listener" concept. People say that C# and Java is very alike, but that's another story when you actually try out both of them and compare.
I have the following auto-generated Action Listener for a button:
btnNewButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
lblNylabel.setText("New label text");
}
});
I understand it like this:
You call a non-static method via the object "btnNewButton" btnNewButton.addActionListener()
The method takes one ActionListener instance as an argument
The automated code instansiates an ActionListener instance via the "new ActionListener()" constructor call - What I don't understand is that I can't instansiate the ActionListener class myself, but it's possible as an argument in the method call??
A "actionPerformed" method is generated inside the new instance body and used here (What?)
Inside the "actionPerformed" method you define what to do, when the button is clicked - Makes perfectly sense
Is it possible to do this in a more understanding/simple way that could help me understand the ActionListener concept?

What I don't understand is that I can't instansiate the ActionListener class myself, but it's possible as an argument in the method call??
When you do
new ActionListener() {
public void actionPerformed(ActionEvent e) {
lblNylabel.setText("New label text");
}
}
You're actually creating an instance of an anonymous subclass of ActionListener.
It is semantically equivalent of doing
class AnonymousActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
lblNylabel.setText("New label text");
}
}
btnNewButton.addActionListener(new AnonymousActionListener());
(And tada, as a bonus, you just learned that you can have method local classes in Java ;-)
Here are a few common alternatives:
Use an separate ordinary class:
class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
lblNylabel.setText("New label text");
}
}
class YourClass {
public void yourMethod() {
...
btnNewButton.addActionListener(new MyActionListener());
}
}
(only possible if the other class has access to the required variables.)
Same as above, but with an inner (non-static) class:
class YourClass {
public void yourMethod() {
...
btnNewButton.addActionListener(new MyActionListener());
}
// Inner class
class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
lblNylabel.setText("New label text");
}
}
}
(Here lblNylabel will probably be in scope for the inner class.)
Let the enclosing class itself implement the ActionListener and use this as argument to addActionListener:
class YourClass implements ActionListener {
public void yourMethod() {
...
btnNewButton.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
lblNylabel.setText("New label text");
}
}

Related

Where would I implement an ActionListener?

Where would I implement the following code? By where I mean do I make a new class? Put it in the constructor of my main class? etc.
public interface ActionListener extends EventListener {
void actionPerformed(ActionEvent e);
}
You need to make a class that implements the interface.
public class ActionListenerExample implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// Do something here
}
}
You can then make an object of the class.
ActionListenerExample listener = new ActionListenerExample();
With Java 8, you could make this more compact by using a lambda expression.
ActionListener listener = action -> {
// Do something
};
If you don't use Java 8 (which you should) but still want to make it compact, use an anonymous class.
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Do something here
}
}
Here's an example implemented as a local variable:
final ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Hello World");
}};

How to reference the class fromasubclass

I am trying to find the answer but I can't. In java, when I create a subclass, how can I reffer the first level class? Using "this" accesses the subclass so I can't. The other option is passing the argument to the subclass but I'm curious if there is a simpliest method.
//here there is my other 1st level class implementation, this is a JFrame
btnNewProject.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
VehicleScreen pp=new VehicleScreen(**here should go the top class reference**);
//v is a JPanel that I pass to allJframes
v.setContentPane(pp);
v.setVisible(true);
}
});
class Foo {
int x;
Foo() {
new Runnable() {
public void run() {
Foo.this.x = 1;
}
}
}
}
You have a couple choices:
Make the variable outside the anonymous class an instance variable:
public class AnonymousClass extends JFrame {
private JLabel label;
...
public AnonymousClass() {
...
btnOk.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setText(textField.getText());
}
});
...
}
You can also access the instance variable as follows:
AnonymousClass.this.label.setText(textField.getText());
Use the final modifier on the local variable:
public class AnonymousClass extends JFrame {
...
public AnonymousClass() {
final JLabel label = new JLabel("Enter a new message!");
btnOk.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
label.setText(textField.getText());
}
});
...
}
Be aware that using the final modifier will mean you cannot re-assign the variable at a later point in your program.

Disable a JButton from a listener that's in a separate class

I'm writing a pretty big class and don't want to post it here. The question is the following, how do I refer to the button that was pressed in the constructor of a different class? Let's say, I want to disable it after some actions in the listener. If the listener were anonymus or were an inner class of the SomeClass, I would just use the name of the variable like this:
button.setEnabled(false);
But how can I do it when my listener is a separate class? Tried using e.getModifiers().setEnabled(false) and e.getSource().setEnabled(false), didn't work.
public class SomeClass extends JPanel {
private JButton button = new JButton("Button");
public SomeClass() {
button.setActionCommand("button");
button.addActionListener(new ButtonListener());
}
public static void main(String[] args) {
// TODO code application logic here
}
}
class ButtonListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
String src = e.getActionCommand();
if (src.equals("button")) {
//some actions here
//then
}
}
}
Try this ((JButton)e.getSource()).setEnabled(false)
It must work)
e.getSource() return component to which this event refers( docs)

Java Individual ActionListeners and an Overarching ActionListener

Perhaps I am going about this the wrong way. Let me know
Using Swing and AWT, I have several buttons set up on a frame and they each have an ActionListener corresponding to their specific function I.E.
JButton foo_button = new JButton("Foo-Me");
foo_button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//Fancy schmancy code work
}
})
JButton bar_button = new JButton("Bar None");
bar_button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//Fancy schmancy code work
}
})
So each of these buttons do their own thing. However, what if I want all the buttons to do a certain thing (the same exact method for each), in my case, clear a label, before they do their own thing.
Obviously I could add whatever_label.setText("") to each actionPerformed() but that entails a lot of duplication, something I'm not so much a fan of.
Oh Java and Swing gurus come to my aid.
You can subclass your own implementation of ActionListener:
private static abstract class MyListener implements ActionListener {
#Override
final public void actionPerformed(ActionEvent evt) {
theSameTask();
uniqueTask(evt);
}
private void theSameTask() {
// the identical task
}
public abstract void uniqueTask(ActionEvent evt);
}
And then, the new listeners will look like this:
JButton bar_button = new JButton("Bar None");
bar_button.addActionListener(new MyListener() {
#Override public void uniqueTask(ActionEvent evt) {
//Fancy schmancy code work
}
});
Another possibility is to use the 'Decorater' pattern, and write an ActionListener decorator for the common behavior. Your code would then be of the form
bar_button.addActionListener(new MyActionListenerDecorator( new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//Fancy schmancy code work
} }) );
I think the best way to do this is to use Action. That way all the listeners always do the same thing.

"this" reference escaping during construction?

If I do the following,
final class FooButton extends JButton{
FooButton(){
super("Foo");
addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
// do stuff
}
});
}
}
am I letting the this reference implicitly escape?
Yes, the this reference escapes to the listener. Since this listener is not really an external class, I don't see any problem with it, though.
Here's where you could see that this escapes:
final class FooButton extends JButton{
Foo(){
super("Foo");
addActionListener(new ActionListener(){
private buttonText = FooButton.this.getText(); // empty string
#Override
public void actionPerformed(ActionEvent e){
// do stuff
}
});
this.setText("Hello");
}
}
Yes, because in the anonymous inner class you could access it like this:
final class FooButton extends JButton {
Foo() {
super("Foo");
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
FooButton button = FooButton.this;
// ... do something with the button
}
});
}
}
The code of the anonymous ActionListener could in principle be called and use the FooButton before the FooButton object is fully initialized.
Yes, the anonymous inner class of ActionListener has a reference to this.
Yes. this of the enclosing class is implicitly in an non-static anonymous class.

Categories

Resources