2

So, I'm trying to define a set of methods for a large set of buttons, and I figured I could do it in a for loop, but I'm getting a syntax error which I can't decipher... Here's a simplified version of the code I want to use... The error is: "Syntax error on token(s), misplaced construct(s)"

JMenu blocks = new JMenu("Block");
menuBar.add(blocks);

for (int i=0; i < 9; i++){
  public void action() {
      System.out.println(i+"");
  }
  JMenuItem blockName = new JMenuItem(i+"");
  blockName.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent arg0) {
          action();
      }
  });
  blocks.add(blockName);
}
3
  • 2
    @PaulTomblin not necessary, both work Commented Sep 25, 2012 at 13:49
  • What line gives you that error? Commented Sep 25, 2012 at 13:49
  • @PaulTomblin actually using String concatenation to convert an int to a String is not a good practice (since behind the scenes you are creating an unnecessary StringBuilder). It is rather recommended to use String.valueOf. And anyway, ""+i will output the same result as i+"". Commented Sep 25, 2012 at 14:08

7 Answers 7

3

Delete your action method and place your code inside the ActionListener

  public void actionPerformed(ActionEvent arg0) {
      System.out.println(i+"");
      // ... etc.
  }

As others have mentioned in their answers, i will not be accessible from within actionPerformed. Specifically, see @dasblinkenlight's answer for a more thorough response.

Sign up to request clarification or add additional context in comments.

Comments

2

Java methods are not first-class objects (or second or third-class objects; in fact, methods are not objects at all). You need to move the method into one of the classes - either your top class, or the anonymous inner class that you defined, like this:

for (int i=0; i < 9; i++) {
    // You cannot access i from methods of the anonymous inner class
    // because it is not final, but you can make a final copy
    final int iCopy = i;
    JMenuItem blockName = new JMenuItem(i+"");
    blockName.addActionListener(new ActionListener() {
        // It is OK to define additional methods here:
        public void action() {
            System.out.println(iCopy+"");
        }
        public void actionPerformed(ActionEvent arg0) {
            action();
        }
    });
    blocks.add(blockName);
}

Comments

2

You are defining a new method inside another method:

  public void action() {
      System.out.println(i+"");
  }

You need to extract this outside of the current method.

Comments

1

That is simply not valid Java. Consider creating an Action instance in your for loop and use that action to back the JMenuItem, e.g.

JMenu blocks = new JMenu("Block");
menuBar.add(blocks);

for (int i=0; i < 9; i++){
    Action action = new AbstractAction(){
      public void actionPerformed( ActionEvent e ){
        System.out.println( "Whatever but not i as that cannot be accessed" );
        System.out.println( "or you need to introduce a final variable" );
      }
    };  
    JMenuItem blockName = new JMenuItem(i+"");
    blockName.setAction( action );  
    blocks.add(blockName);
}

Comments

1

You can not have a method declartion insede for loop. The loop must be in a method body.

 private void init(JMenu blocks) {
   for (int i=0; i < 9; i++){

    JMenuItem blockName = new JMenuItem(i+"");
    blockName.addActionListener(new ActionListener() {
          public void actionPerformed(ActionEvent arg0) {
              handleAction(arg0);
          }
      });
    blocks.add(blockName);
  }
}


   public void handleAction(ActionEvent event) {

       Object source = event.getSource(); 

       if(source instanceof JMenuItem) {
           JMenuItem item = (JMenuItem) source;
           System.out.println(item.getName());
       ) 
   }

Comments

1

You can also do this

    for (int i = 0; i < 9; i++) {
        JMenuItem blockName = new JMenuItem(i + "");
        blockName.setAction(new MyAction(i));
        blocks.add(blockName);
    }
}

class MyAction extends AbstractAction {
    int param;

    public MyAction(int myParameter) {
        param = myParameter;
    }

    public void actionPerformed(ActionEvent e) {
        System.out.println(String.valueOf(param));
    }
}

Comments

0

You can'd define nested methods, just nested classes [inner classes], or a class nested in a method [local classes].

If you want your ActionListener to be aware of the i, you can't directly, or you will stumble upon such error:

local variable i is accessed from within inner class; needs to be declared final

so you should extend your JMenuItem, or better design your application in order to decouple UI from current model status.

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.