I'm writing a Swing application and trying to make a menu where each menu item has its own action:
Here's how I wanted to solve this:
private void createGameLevelMenuItems(JMenu menu){
for (int i = 0; i<10; i++) {
JMenuItem item = new JMenuItem(new AbstractAction("Level-" + i) {
@Override
public void actionPerformed(ActionEvent e) {
game.loadGame(i);
board.refresh();
pack();
}
});
menu.add(item);
}
}
However, I cannot use loadGame(i)
, because it says i
would have to be final. I understand the reason for this, but I do not know how to work my way around it.
Often the variable that controls a for loop is needed only for the purposes of the loop and is not used elsewhere. When this is the case, it is possible to declare the variable inside the initialization portion of the for.
It's the result of JVM specifications... But in the name of best coding practice it is recommended to declare the variable in the smallest possible scope (in this example it is inside the loop, as this is the only place where the variable is used). It is the result of the JVM Soecification, not 'compiler optimization'.
In Python, on the other hand, variables declared in if-statements, for-loop blocks, and while-loop blocks are not local variables, and stay in scope outside of the block.
Quick trick: define a final variable at each iteration of the loop that takes the (non final) value of i
and use it:
private void createGameLevelMenuItems(JMenu menu){
for (int i = 0; i<10; i++) {
final int j = i; // <--- this line do the thing
JMenuItem item = new JMenuItem(new AbstractAction("Level-" + j) {
@Override
public void actionPerformed(ActionEvent e) {
game.loadGame(j);
board.refresh();
pack();
}
});
menu.add(item);
}
}
To add an example to my comment above. You could just create a class implementing AbstractAction, store the i in instance variable and provide it via constructor:
private void createGameLevelMenuItems(JMenu menu){
for (int i = 0; i<10; i++) {
JMenuItem item = new JMenuItem(new LoadAction(i));
menu.add(item);
}
}
private class LoadAction extends AbstractAction {
private int i;
public LoadAction(int i) {
super("Level-" + i);
this.i = i;
}
@Override
public void actionPerformed(ActionEvent e) {
game.loadGame(i);
board.refresh();
pack();
}
};
This assumes the game and board are final variables in the encapsulating class, but since you have just a problem with i
, I guess it's the case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With