Running a "this" Method inside actionPerformed - JButton? - java

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;
}
}

Related

Rewriting the code so that its readability is improved without changing its behaviour

public class A2 {
public class B implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Fing");
}
}
public class C implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Fang");
}
}
public class D implements ActionListener{
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Foom");
}
}
public A2(){
JButton a = new JButton("Fing");
JButton b = new JButton("Fang");
JButton c = new JButton("Foom");
a.addActionListener(new B());
b.addActionListener(new C());
c.addActionListener(new D());
}
public static void main(String[] args) {
A2 a2 = new A2();
}
The problem I encountered is quite simple, but complex. I want it to shorten the code without retouching its functionality. For example, the code is showing to many actionlisteners and actionperformed, and I was trying to make it one class pulling out System.out.println(); and putting in String value on it. However, the coding does not work in this simple ways. Please help me out to curtail this code as simple and increase the readability. Thanks.
It's impossible to know what things you could do, I'm personally a fan of self documenting code, so sometimes, you need to be careful when trying to optimise solutions.
My first thought might be to start with the Action's API, which allows you to design a self contained unit of work
public class CommonAction extends AbstractAction {
public CommonAction(String name) {
putValue(NAME, name);
putValue(SHORT_DESCRIPTION, "This is a tool tip for " + name);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(getValue(NAME));
}
}
You could extend it further to provide more customisation if you needed, overriding the actionPerformed method, but, that's up to you.
Then you just need to apply to your buttons...
public class A2 {
public A2() {
JButton a = new JButton(new CommonAction("Fing"));
JButton b = new JButton(new CommonAction("Fang"));
JButton c = new JButton(new CommonAction("Foom"));
}
}
Or your menu's or your key bindings, Action is a rather flexible API supported by a number of other components
You can define single class MyActionListener which implements ActionListener as shown below:
public class MyActionListener implements ActionListener {
private String input;
public MyActionListener(String input) {
this.input = input;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(input);
}
}
public A2(){
String[] inputs = {"Fing","Fang","Foom"};//Array of JButton inputs
for(int i=0;i<inputs.length;i++) {
JButton jButton = new JButton(inputs[i]);//create JButton instance
jButton.addActionListener(new MyActionListener(inputs[i]));
}
}

Use method as event listener instead of class

I always make an event listener for buttons and such like this:
class MyClass implements extends JPanel implements ActionListener{
JButton btn1, btn2, btn3;
public Myclass(){
....
btn1 = new JButton("button 1");
btn1.addActionListener(this);
....
}
public void actionPerformed(ActionEvent e) {
Object action = e.getSource();
if(action = btn1){
functionForBTN1();
}
else if(action = btn2){
functionForBTN2();
}
else if(action = btn3){
functionForBTN3();
}
}
public void functionForBTN1(){...}
public void functionForBTN2(){...}
public void functionForBTN3(){...}
}
Is it possible to direct the event directly to a method instead of the actionPerformed() method? something like (pseudo-code):
class MyClass implements extends JPanel implements ActionListener{
JButton btn1, btn2, btn3;
public Myclass(){
....
btn1 = new JButton("button 1");
btn1.addActionListener(this.functionForBTN1());
....
}
public void functionForBTN1(){...}
public void functionForBTN2(){...}
public void functionForBTN3(){...}
}
If you're using Java 8, you can accomplish this using a lambda expression.
btn1.addActionListener(e -> this.functionForBTN1());
Prior to Java 8, you could create an anonymous ActionListener to acomplish the same task.
btn1.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e){
this.functionForBTN1();
}
});
You can use anonymous classes:
btn1.addActionListener(new ActionListener (){
public void actionPerformed(ActionEvent e) {
// ....
}
});
However, if you want to add it like you did in your second snippet, you can do something like:
final ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(final ActionEvent e) {
if (e.getSource() == btn1) {
//...
} else if (e.getSource() == btn2) {
//...
}
}
};
And then:
btn1.addActionListener(listener);
btn2.addActionListener(listener);
I personally prefer anonymous classes as long as they're readable and not too long.
As Maroun Maroun said an anonymous class is a good idea. With java-8 you could also use a lamdba which makes the code slightly nicer;
btn1.addActionListener(event -> functionForBTN1());

Make a class that have "addActionListener" method

i'm doing a class that does a sort of "file explorer",
in the constructor i create the frame ,panel ecc.. but than i want to say to the main program that calls this class that the user has finish the selection, i know i can call a static method that is in the main from this class,but i want to make a action listener because i want to use this class for different programs
For Example if FileEx is my class:
public class FileEx()
{
public FileEx()
{
//program that do something
if(done == true)
//here i want to call the action
}
public void addActionListener(ActionListener ac) //i don't know if it's correct
//but i want something like this
{
}
}
public static void main(String[] args)
{
FileEx fileex = new FileEx();
fileex.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e)
{
//when done is true i want this block of code to be called
}
});
}
ActionListeners will only work when added to components that allow them to be added and that notify listeners with them such as JButtons, JMenuItems, JComboBoxes and such. We have no idea what type of class FileEx is or why it should accept an ActionListener and a little more information would be qutie helpful. If you want to notify another object that an event occurs, such as that a calculation is done, use another type of listener such as a PropertyChangeListener. Alternatively you could do the processing in a modal JDialog window, which will notify the calling window that it is done performing its duties by returning code flow to the calling window.
For example, please look at my answers to similar questions:
Drawing with paintComponent after value of Jbutton changed in another class
JTextField data in different frames, with data stored in global variable?
Loop making program freeze
EDIT
For example, if you wanted your FileEx to allow other classes to listen for changes to a String called selection (the so-called "bound" property) you could create it to look something like:
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
public class TestFileEx {
public static void main(String[] args) {
final FileEx fileEx = new FileEx();
fileEx.addPropertyChangeListener(FileEx.SELECTION, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
// TODO code to call when fileEx has changed selections
String fileExSelection = evt.getNewValue().toString();
// or
String fileExSelection2 = fileEx.getSelection();
}
});
}
}
and
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.event.SwingPropertyChangeSupport;
publicclass FileEx {
public static final String SELECTION = "selection";
private SwingPropertyChangeSupport propertyChangeSupport = new SwingPropertyChangeSupport(
this);
private String selection;
public void someMethodThatChangesSelection() {
}
public String getSelection() {
return selection;
}
public void setSelection(String selection) {
String oldValue = this.selection;
String newValue = selection;
this.selection = selection;
// notify the listeners of change
propertyChangeSupport.firePropertyChange(SELECTION, oldValue, newValue);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
public void rem(String propertyName, PropertyChangeListener listener) {
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
}
}
Here is the code based on your example which adds actionlisteners and calls them:
public class FileEx()
{
private final List<ActionListener> listeners = new ArrayList<>();
public FileEx()
{
//program that do something
if(done == true) {
notifyListeners();
}
}
public void addActionListener(ActionListener ac)
{
listeners.add(ac);
}
private void notifyListeners()
{
for (final ActionListener listener: listeners)
{
listener.actionPerformed(null);//You can create event if you want.
}
}
}
public static void main(String[] args)
{
FileEx fileex = new FileEx();
fileex.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e)
{
//when done is true i want this block of code to be called
}
});
}

Class of Event handlers

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).

Nested class vs implements ActionListener

Are there any benefits or drawbacks to creating a nested class that implements ActionListener:
public class Foo{
Foo(){
something.addActionListener(new ButtonListener());
}
//...
private class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
//...
}
}
}
versus implementing ActionListener in the main class itself:
public class Foo implements ActionListener{
Foo(){
something.addActionListener(this);
}
//...
public void actionPerformed(ActionEvent e){
//...
}
}
I've seen both examples quite often, and just want to know if there's a 'best practice.'
#Ankur, you can still use anonymous inner classes as your listeners and have a separate free-standing control class and thus have code that's quite maintainable, a technique I like to use a bit. For example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AnonymousInnerEg {
private static void createAndShowUI() {
GuiPanel guiPanel = new GuiPanel();
GuiControl guiControl = new GuiControl();
guiPanel.setGuiControl(guiControl);
JFrame frame = new JFrame("AnonymousInnerEg");
frame.getContentPane().add(guiPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class GuiPanel extends JPanel {
private GuiControl control;
public GuiPanel() {
JButton startButton = new JButton("Start");
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (control != null) {
control.startButtonActionPerformed(e);
}
}
});
JButton endButton = new JButton("End");
endButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (control != null) {
control.endButtonActionPerformed(e);
}
}
});
add(startButton);
add(endButton);
}
public void setGuiControl(GuiControl control) {
this.control = control;
}
}
class GuiControl {
public void startButtonActionPerformed(ActionEvent ae) {
System.out.println("start button pushed");
}
public void endButtonActionPerformed(ActionEvent ae) {
System.out.println("end button pushed");
}
}
I think first approach is better, as your class will have a separate code for handling action. And usually also composition is better than inheritance so a class should extend a class or implement a interface only if it truly is-a super type.
Also for maintainability, let us say Foo class has a new requirement to listen for another different type of events and then perform action, in that case also first class can be easily modified.
If I am not worried about maintainability I would rather go for a anonymous class.
If the class Foo has no other responsibility than encapsulating this button, then the first solution is sort of ok.
However, as soon as Foo gets more "somethings" that it has to listen to then it gets messy. I prefer the second solution since it is more explicit and has a better scalability.
An even better solution may be to create an anomymous inner class.
public class Foo{
Foo(){
something.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
//...
}
});
}
}
Usually you want to use a nested or even anonymous class rather than exposing ActionListener to the API of the enclosing class. (public class Foo implements ActionListener -> Javadoc will state that Foo is an ActionListener, though this is usually just an implementation detail -> bad)

Categories