0

I have been trying to change the position of my JButton in the action listener. However, when I compiled my code Local variable is accessed from within inner class: needs to be declared final error was displayed. Therefore, I declared my location variable as final. The problem is that I need to change the value of my location variable and that is not possible as long as its final. How do I solve this?

Code:

final int location =100;

JFrame f = new JFrame();
final JButton b1 = new JButton("character");

f.setVisible(true);
f.setSize(500,500);
f.setDefaultCloseOperation(EXIT_ON_CLOSE);
f.setLocationRelativeTo(null);
f.setLayout( new FlowLayout());

f.add(b1);

b1.addActionListener(new ActionListener() {     
  public void actionPerformed(ActionEvent e) {
     b1.setLocation(location,100);
     location += 10; // cannot assign a value to final variable location
  }
});
Ambrish
  • 3,627
  • 2
  • 27
  • 42

5 Answers5

2

You are trying to reference the button that was clicked. The ActionEvent contains the source of the event which will be the button. So your code should be:

//b1.setLocation(location,100);
JButton button = (JButton)e.getSource();
button.setLocation(button.getLocation() + 10, 100);

Now there is no need for a location variable.

Whenever possible you should use the source of the event to get the Object. Don't depend on instance variables.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • you solution is correct for the purpose, just that , here initially you are setting buttons location (which i think should be `b1.setLocation((int) (b1.getLocation().getX()+10), 100);`) incremented by 10. where as user is setting a fix initial value, and incrementing it, to be set in next event invocation. – Shailesh Aswal Jun 11 '14 at 05:23
  • @Shail016, yes you are correct, my example is not very good based on the code presented. But the code presented doesn't make much sense either. The frame is using a FlowLayout so you should not be trying to set the location of the button, that is the job of the layout manager. Since a FlowLayout is used, the initial location of the button would be with an "x" value of 5. So it didn't make much sense to jump to 100 on the first click, but then increment by 10 on every other click. I was mostly trying to demonstrate that you can get the component that was clicked from the event itself. – camickr Jun 11 '14 at 05:36
  • true, the initial location would still be the one provided by the underneath layout manager. "jumping to 100 and then moving 10 points horizontally" might make sense to the user :) – Shailesh Aswal Jun 11 '14 at 05:56
0

Not possible with the local variable.
Rather wrap your implementation in a class. Try something like:

  class Test {
         //instance variable
            private int location = 100;

            void init() {

                JFrame f = new JFrame();
                final JButton b1 = new JButton("character");
                f.setVisible(true);
                f.setSize(500, 500);
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setLocationRelativeTo(null);
                f.setLayout(new FlowLayout());

                f.add(b1);

                b1.addActionListener(new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        b1.setLocation(location, 100);
                        Test.this.location += 10;
                    }
                });
            }
        }

or even below should work fine (in case you don't need location anywhere else):

b1.addActionListener(new ActionListener() {

        private int location = 100;

        @Override
        public void actionPerformed(ActionEvent e) {
            b1.setLocation(location, 100);
            location += 10;
        }
    });
Shailesh Aswal
  • 6,632
  • 1
  • 20
  • 27
0

I am not sure about what the code is trying to do but the general idea is that Final primitive variables are immutable. However in case of object references, its the reference which can't be changed but the instance variables of the object can be changed. For example if you were to use a Map to store location say like below

final Map<String,Integer> locM=new HashMap<String,Integer>();
locM.put("location",100);
then you can do the change to map values

b1.addActionListener(new ActionListener() {     
public void actionPerformed(ActionEvent e) {
..............
 locM.put("location",locM.get("location")+10);
   }
 });

Or you can create a Location wrapper class which has setter and getter for int location value. In case of int, the wrapper class Integer is immutable so you will need to define your own.

Monmohan

factotum
  • 900
  • 10
  • 13
0

If Location is a instance variable rather than a Local variable you can avoid this particular problem

Trasvi
  • 1,207
  • 1
  • 15
  • 23
0

You can do it in two ways,

1) Implement ActionListener to your parent class then in

ParentClass implements ActionListener 
{
int location =100;
 //...Codes codes..
 public void actionPerformed(ActionEvent e) {
 //perform null check 
  if (b1==(JButton)e.getSource()){
   b1.setLocation(location,100);
    location += 10;

    }
  }
}

2) Call static variables from inner class, (remember: This is a bad method of programming)

 //static class to store variables
  Class StaticVariables{
  static int location=100;
 }



class ParentClass{

    //..Codes Codes..

    b1.addActionListener(new ActionListener() {
    //Calling Static class varible
    int localLocationVariable=StaticVariables.location;
    b1.setLocation(localLocationVariable,100);
    localLocationVariable+= 10;
    StaticVariables.location=localLocationVariable;
    }

Hopes this may help you.

Nithin CV
  • 1,046
  • 9
  • 23