I am creating a generic method to create action listeners for buttons, and i would like to be able to pass in another method into it's actionPerformed, rather than creating a new method for each use case of a listener. something like this:
public static ActionListener makeListener(Method method) {
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
method();
}
};
return listener;
}
Other similar posts have had recommended Lambda Expressions, but (maybe due to a lack of understanding), I don't think those are what i need. Are there other options?
Sounds like a Runnable is exactly what you need.
Declaration:
public static ActionListener make_listener(JButton button, Runnable action) {
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
action.run();
}
};
return listener;
}
Or using a lambda for the ActionListener (and skipping the local variable):
public static ActionListener make_listener(JButton button, Runnable action) {
return e -> action.run();
}
You can now call it with any zero-argument method using a lambda or method reference:
ActionListener listener1 = make_listener(() -> callMethod());
ActionListener listener2 = make_listener(this::callMethod);
Related
I want to find the best practice to separate actionListener to an individual class. Throughout my research , the only things that i found is to create one actionlistener for one class.java which did not solve my issue.
For an example ,
launch.java
public class launch {
public launchSystem(){
....
JButton click1 = new JButton("Click 1");
JButton click2 = new JButton("Click 2");
//--- Add actionListener
// click1.addActionListener(new clickAction_b);
frame.add(click1);
frame.add(click2);
}
}
listenerClass.java
public class listenerClas {
class clickAction_A implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("click a");
}
}
class clickAction_B implements ActionListener{
#Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("click b");
}
}
}
In this case , i want to add "clickAction_b to my cliaddActionListener" but unable to do so . I tried using extend and interface but all failed. Is it even possible to linked multiple actionlistener like calling a method from a different class?
I have a JButton which I added a actionPerformed, and I tried to write a "this" method and it won't allow it. How can I do this? This is example of what I want to do:
public void methodName(String results) {
this.results = results;
}
Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
this.methodName(asdf);
}
Because it's an anonymous class, using this will refer to the anonymous class instance, not your overall class. To get around this, denote that you want to reference your outer class specifically:
Something some = new Something() {
public void overridden() {
YourClass.this.methodName("test");
}
};
Your class in anonymous, so in anonymous context, this does not make any sense. What do you mean by this? If you mean the button, your answer is event.getSource()
In your code, this refers to your ActionListener when you call the method.
If you want to call methodName() from the enclosing class, you have two choices :
remove this:
Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
methodName(asdf);
}
store a reference to the enclosing class and use it:
final MyClass enclosingClass = this;
Button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
enclosingClass.methodName(asdf);
}
You can not use "this" keyword inside inner class to access outer class method. if we use this then it will refer to the inner class.Instead of that just use the method name.see the example.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
public class TestButton
{
String results = "";
JButton Button = new JButton();
public TestButton(){
Button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
methodName("Test");
this.show();
}
public void show(){
System.out.println("hi");
}
});
}
public void methodName(String results)
{
this.results = results;
}
}
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I have a simple GUI which contains:
a push button.
Two radio buttons
Now I want to listen to each one of these buttons. What I do is something like that:
public class TestApp implements ActionListener {
private JFrame frame;
private JButton btn;
private JRadioButton rdb1;
private JRadioButton rdb2;
public static void main(String[] args) { /*....*/ }
private void initialize() {
//Each time I add a button, I add it to the listener:
btn = new JButton("Button");
btn.addActionListener(this);
//..
rdb1 = new JRadioButton("Value1");
rdb1.addActionListener(this);
//And so on...
}
//The ActionEvents
public void actionPerformed(ActionEvent e) {
if(e.getSource()==btn)
//...
if(e.getSource()==rdb1)
//...
}
}
Now I want to know if this considered a good/bad style?
Unless the listener is a very long method, I personally prefer the anonymous class pattern:
final JButton btn = new JButton("Button");
final JRadioButton rdb1 = new JRadioButton("Value1");
final ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
if (e.getSource() == btn) {
//...
} else if (e.getSource() == rdb1) {
//...
}
}
};
btn.addActionListener(listener);
rdb1.addActionListener(listener);
or even better:
btn.addActionListener(new ActionListener (){
public void actionPerformed(ActionEvent e) {
// btn handling code
}
});
rdb1.addActionListener(new ActionListener (){
public void actionPerformed(ActionEvent e) {
// rdb1 handling code
}
});
The pattern you are using allows other class to set the class TestApp to be set as a listener by other classes - unless this is intended, it is not a good practice.
A lot comes down to the complexity of what the action listener is trying to do. If you want small, single use actions, then an anonymous class would suitable.
The main benefit of using this style of listener is it will isolate exactly what the action is doing and who it's doing it for. The drawback comes when the listener contains more then, say, 10 or more lines, as it starts to becoming difficult to read and know where the listener actually ends.
In this case, something like a inner class might be more suitable. It has the benefit of an anonymous class (being tied to the class that uses it), but is easier to read.
If you want reusable actions (think of things like open, new, save), then you're better off using the Action API, which provides self configurability as well a self contained action listener
IMHO
More object-oriented way is to create an anonymous class for implementation of each of the listeners.
Creating only one listener that switches on the event source component is not very readable, but moreover, when the number of listeners increases, it becomes error prone. You can easily forget to handle all of the possible event sources in the switch block (or a chain of if-else blocks), which will result in a runtime exception silent wrong behaviour (nothing would happen for that case).
Adding individual listeners to each of the components will give you compile-time checking that you haven't forgotten to handle all of them.
public class TestApp {
// you can initialize fields inline to make thing shorter and safer
private JButton btn = new JButton("Button");
private JRadioButton rdb1 = new JRadioButton("Value1");
private void initialize() {
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// something
}
});
rdb1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// something else
}
});
}
}
Because the anonymous class syntax is very verbose, you can shorten the code of the initialize method by moving the listeners into private fields.
public class TestApp {
private JButton btn = new JButton("Button");
private JRadioButton rdb1 = new JRadioButton("Value1");
private void initialize() {
btn.addActionListener(btnListener);
rdb1.addActionListener(rb1Listener);
}
private final ActionListener btnListener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// something
}
};
private final ActionListener rb1Listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// something else
}
};
}
You can think about two other ideas:
Give each UI element its own Listener; they're completely independent that way.
Inject the Listeners into your Swing UI rather than calling new. You give users the opportunity to change the behavior as they see fit. Let your Swing UI do what it was meant to do: display results. That's it. I would argue that Listeners are part of the Controller logic.
It depends to a certain extent on what you want to do in the actionPerformed method. If no other class is likely to want to call this method then I may be tempted to reduce the scope of the actionPerformed method by creating an inner class e.g.:-
public class TestApp {
private JFrame frame;
private JButton btn;
private JRadioButton rdb1;
private JRadioButton rdb2;
private class CombinedActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(e.getSource()==btn)
//...
if(e.getSource()==rdb1)
//...
}
}
public static void main(String[] args) { /*....*/ }
private void initialize() {
ActionListener listener = new CombinedActionListener()
//Each time I add a button, I add it to the listener:
btn = new JButton("Button");
btn.addActionListener(listener);
//..
rdb1 = new JRadioButton("Value1");
rdb1.addActionListener(listener);
//And so on...
}
}
You could even make the listener class a static inner class or a top-level class by passing the button instances into the constructor - which would make the listener class easier to test.
As I said above though, this is largely dependent on i) if anyone else is likely to call this method and ii) the complexity of the logic inside the method.
is it possible in java to have a class where it has EventHandlers for with different functions? for example button1 will log you in, while button2 will log you out, is this possible? Here's the code I made it seems to be not working.
package event.handlers;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TheHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent logInEvent) {
System.out.println("Button Login");
}
public void actionPerformed(ActionEvent cancelEvent) {
System.out.println("Cancel Login");
}
}
You either need two implementations of ActionListener, one for each button or the actionPerformed needs to determine the button by the event argument and take the appropriate action. Your code will not compile because the signatures for both methods are the same.
No. You can not have a class implement two methods with the same function signature. How would the compiler know which one to call for different events? The name you give to the arguments has no meaning to the compiler.
As an alternative, you can create multiple anonymous action listeners that simply forward the call to a method that does have a unique name if you want everything to be in the same class.
public class TheHandler {
public TheHandler() {
JButton login, cancel;
//initialize code here
login.addActionListener( new ActionListener() {
#Override
public void actionPerformed(ActionEvent logInEvent) {
loginPerformed(logInEvent);
}
});
cancel.addActionListener( new ActionListener() {
#Override
public void actionPerformed(ActionEvent cancelEvent) {
cancelPerformed(cancelEvent);
}
});
}
public void loginPerformed(ActionEvent logInEvent) {
System.out.println("Button Login");
}
public void cancelPerformed(ActionEvent cancelEvent) {
System.out.println("Cancel Login");
}
}
You may use getSource() or getActionCommand() method of ActionEvent.
#Override
public void actionPerformed(ActionEvent logInEvent) {
Object src=logInEvent.getSource();
String cmd=logInEvent.getActionCommand(); //It will return caption of button
if(src==btn1)
{
//
}
//Or
if(cmd.equals("Button1")) { ... }
}
You can not have multiple actionPerformed method in one class. Simple way is to do operation based on source of action like:
(in actionPerformed method)
if(e.getSource() == loginButtton) { // based on button variable if they are in same class and accessible in actionPerformed method
loginMethod()
} else if(e.getSource == logoutButton) {
logoutMethod()
}
or
if(e.getActionCommand().equals("loginButtton")) { // based on caption/text on button
loginMethod()
} else if(e.getActionCommand().equals("logoutButtton")) {
logoutMethod()
}
or you can have different anonymous class for different buttons like
loginButton.addActionListner(new ActionListerner(){
public void actionPerformed(ActionEvent loginEvent) {
loginMethod();
}
});
logoutButton.addActionListner(new ActionListerner(){
public void actionPerformed(ActionEvent cancelEvent) {
logoutMethod();
}
});
The problem there is that your two method signatures are identical. When Java tries to figure out which method to call, it can't tell the difference between the two.
I can think of two ways to do what you want:
Presumably, you are registering the listeners on the buttons like cancelButton.addActionListener(...). So you can either provide each button with its own anonymous inner class:
loginButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent logInEvent) {
System.out.println("Button Login");
}
}
cancelButton.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent cancelEvent) {
System.out.println("Cancel Login");
}
}
or you can define a single actionPerformed method that checks the source of the call:
public class TheHandler implements ActionListener {
JButton loginButton;
JButton cancelButton;
public TheHandler()
{
...
// Now, technically, this is bad form because you're leaking 'this'.
// But as long as this will only be called after this constructor finishes
// initializing, it's safe.
loginButton.addActionListener(this);
cancelButton.addActionListener(this);
...
}
...
#Override
public void actionPerformed(ActionEvent evt) {
if(evt.getSource() == loginButton)
System.out.println("Button Login");
else if(evt.getSource() == cancelButton)
System.out.println("Cancel Login");
}
}
Using anonymous inner classes can sometimes be clearer, because you see the code right next to the addListener call, but it also adds a lot of boilerplate, and if you're working on a very large progect that can take a while to load, reducing the number of classes can sometimes make it load a little faster (each anonymous inner class is another thing for the JVM to load).
How would I go about writing a constructor for an inner class which is implementing an interface? I know I could make a whole new class, but I figure there's got to be a way to do something along the line of this:
JButton b = new JButton(new AbstractAction() {
public AbstractAction() {
super("This is a button");
}
public void actionPerformed(ActionEvent e) {
System.out.println("button clicked");
}
});
When I enter this it doesn't recognize the AbstractAction method as a constructor (compiler asks for return type). Does anyone have an idea?
Just insert the parameters after the name of the extended class:
JButton b = new JButton(new AbstractAction("This is a button") {
public void actionPerformed(ActionEvent e) {
System.out.println("button clicked");
}
});
Also, you can use an initialization block:
JButton b = new JButton(new AbstractAction() {
{
// Write initialization code here (as if it is inside a no-arg constructor)
setLabel("This is a button")
}
public void actionPerformed(ActionEvent e) {
System.out.println("button clicked");
}
});
If you really need a contructor for whatever reason, then you can use an initialization block:
JButton b = new JButton(new AbstractAction() {
{
// Do whatever initialisation you want here.
}
public void actionPerformed(ActionEvent e) {
System.out.println("button clicked");
}
});
But you can't call a super-class constructor from there. As Itay said though, you can just pass the argument you want into the call to new.
Personally though, I would create a new inner class for this:
private class MyAction extends AbstractAction {
public MyAction() {
super("This is a button.");
}
public void actionPerformed(ActionEvent e) {
System.out.println("button clicked");
}
}
then:
JButton b = new JButton(new MyAction());
The resulting class is not of type AbstractAction but of some (unnamed, anonymous) type that extends/implements AbstractAction. Therefore a constructor for this anonymous class would need to have this 'unknown' name, but not AbstractAction.
It's like normal extension/implementation: if you define a class House extends Building and construct a House you name the constructor House and not Building (or AbstractAction just to com back to the original question).
The reason the compiler is complaining is because you are trying to declare a constructor inside your anonymous class, which is not allowed for anonymous classes to have. Like others have said, you can either solve this by using an instance initializer or by converting it to a non-anonymous class, so you can write a constructor for it.