2

I'm trying to write my first Swing app, it is a simple chess engine in Java. I've made a grid of JButtons to represent squares. Looks ok, but I've come across a problem when trying to add ActionListeners to each square. I want to get squares co-ordinates and print it to console when its clicked. This is what I tried(I guess I don't really understand how ActionListeners work):

// chessBoardSquares[][] is an 8x8 array of Jbuttons

for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {

            chessBoardSquares[i][j].addActionListener(new ActionListener(){

                @Override
                public void actionPerformed(ActionEvent e) {

                    System.out.println("x: "+i+"y: "+j);

                }

            });
        }
    }
4
  • 1
    How does this not work? Does it compile? Run? Misbehave? Throw an exception? Something else? Commented Apr 29, 2015 at 16:00
  • Ah, I see -- you need final variables that's it Commented Apr 29, 2015 at 16:01
  • Cannot refer to the non-final local variable i defined in an enclosing scope Cannot refer to the non-final local variable j defined in an enclosing scope Commented Apr 29, 2015 at 16:04
  • I guessed as much. See answer below. Commented Apr 29, 2015 at 16:05

2 Answers 2

3

You need to use either fields or final local variables inside an anonymous inner class.

for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {
        final int finalI = i;
        final int finalJ = j;

        chessBoardSquares[i][j].addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("x: " + finalI +"y: " + finalJ);
            }
        });
    }
}
5
  • Effectively final is enough, so final modifiers are optional.
    – Bubletan
    Commented Apr 29, 2015 at 16:07
  • @EasternDude: glad you've got it solved. For more details on the underpinnings of this, please check out this link (which I found after answering this question). Commented Apr 29, 2015 at 16:15
  • 1
    @HovercraftFullOfEels Actually, it seems to be a new improvement for Java 8. So if you're having an older version, it won't compile.
    – Bubletan
    Commented Apr 29, 2015 at 16:16
  • 1+, @Bubletan, this code works fine for me using JDK7.
    – camickr
    Commented Apr 29, 2015 at 18:24
  • @camickr Yes, this works with JDK7. The one in my answer shouldn't, as far as I'm right.
    – Bubletan
    Commented Apr 29, 2015 at 18:32
2

Starting from Java 8, you can have use both final and effectively final variables inside anonymous classes (or lambda expressions). An effectively final variable is not declared as final, but its value is never changed.

Your code could be written like this:

for (int i = 0; i < 8; i++) {
    for (int j = 0; j < 8; j++) {

        int finalI = i; // no final modifier
        int finalJ = j;

        chessBoardSquares[i][j].addActionListener(e -> {
            System.out.println("x: " + finalI + "y: " + finalJ);
        });
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.