views:

63

answers:

4

I am writing a setonclick listner, and I want to be able to refer to that button so that I can change its properties. I.e. make it disabled?

I get thismessage:

Cannot refer to a non-final variable confirmButton inside an inner class defined in a different method

        confirmButton.setOnClickListener(new View.OnClickListener() {

        public void onClick(View view) {
            confirmButton.setEnabled(false);    
        }



    }); 
+1  A: 

This because you are probably trying to access that button from an anonymous class that you use in this way:

button.addActionListener(
  new MyListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      //do your things on button }
    }
  }
);

This doesn't work because in Java anonymous classes cannot see variables declared in methods in which they are declared too since their scope are separated. The only way to let your class see it is forcing the final constraint which assures the compiler that the variable won't change after being initialized, allowing it to extend its scope to the anonymous classes.

To quickly fix this you can access the button from the ActionEvent inside the actionPerformed:

((JButton)e.getSource()).setEnabled(false)

Otherwise you have to concretely declare your ActionListener somewhere or declare the buttons outside the method with static or final attribute.. especially if you plan to modify some elements by an action that is fired by another element.

Jack
+1 Just wanted to add ... Or your class can implement ActionListener and then access it as a local variable from inside actionPerformed.
Romain Hippeau
A: 

vars that are referenced within anonymous classes need to be defined as final in Java. Jon Skeet has a great example of this nestled within this article.

akf
+1  A: 

I would recommend against the getSource; the documentation doesn't promise that it will be your button. You can either make your button final in the scope, or use a more sophisticated class

public class ComponentRelevantOnClickListener implements View.OnClickListener {

  private JComponent component;

  public ComponentRelevantOnClickListener(JComponent component) {
    this.component = component;
  }
}

// then, in your code...

confirmButton.setOnClickListener(new ComponentRelevantOnClickListener(confirmButton) {

    public void onClick(View view) {
        component.setEnabled(false);    
    }
});

If you move toward a design of action and listener classes instead of anonymous subclasses, you get more chance for re-use (you can already see that ComponentRelevantOnClickListener could be replaced with a "DisableOnClickListneer" that you can use anywhere for this purpose), and your code will be overall better designed.

davetron5000
A: 

Anonymous inner classes can only access variables from the outer scope if they are final. Assuming you only assign to the confirmButton once, I suggest simply tagging it as final.

final JButton confirmButton = new JButton();
SingleShot