我在下面的for循环中遇到了一个大问题,我正在尝试为一系列JButton创建动作侦听器,并且每个JButton都必须为“Column”和“Row”分配不同的值,但是,对于所有按钮'Column'和'Row'只是for循环的最高可能值,就像在for循环m上升到7,'Column'对所有按钮等于7,它没有实现。换句话说,我想要第一个按钮'但是[0] [0]'使'Column'等于0,但我也想要'但是[1] [0]'使'Column'等于1,所以上。任何帮助将不胜感激。
按钮的目的是更改程序中其他位置声明的“列”和“行”的值,因此每个按钮需要使“列”和“行”等于不同的值。
for (m = 0; m < width; m++){
for (n = 0; n < width; n++){
but[m][n].addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e){
Column = m;
Row = n;
enablenumbers();
disablecolumns();
disablerows();
choose.setText("Now Choose The Nummber You Want To Put In This Square");
}
}
);
}
}
答案 0 :(得分:4)
我猜m
和n
被声明为周围类中的字段(否则ActionListener无法访问它们,即会出现编译错误。)
单击操作时将调用actionPerformed方法。那时,for循环已完成执行,在字段m
和n
中保留最大列和行数。换句话说,所有动作侦听器都访问相同的m
和n
,但它们都应该看到不同的值。
这已经暗示了解决方案:每个ActionListener都需要自己的变量m
和n
。在代码中:
final int col = m;
final int row = n;
but[m][n].addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e){
Column = col;
Row = row;
enablenumbers();
disablecolumns();
disablerows();
choose.setText("Now Choose The Nummber You Want To Put In This Square");
}
}
);
请注意,变量是在内部for循环中声明的;它们只存在于一次迭代中。因为它们是最终的,所以它们对匿名内部类是可见的(在引擎盖下,这些最终变量的值将被复制到匿名类的字段中(此声明的证据在本答案的附录中给出)
或者,您可以采用显式路由并使用内部类:
class MyActionListener implements ActionListener {
final int col;
final int row;
// constructor goes here
// impl of actionPerformed goes here, using col and row instead of m and n
}
您将使用
附加for (m = 0; m < width; m++){
for (n = 0; n < width; n++){
but[m][n].addActionListener(new MyActionListener(m,n));
}
}
附录:内部类封闭变量访问的实现
对于在内部类访问的封闭范围中声明的每个最终局部变量,编译器会自动在内部类中创建一个附加字段来保存其值,并修改构造函数以从新构造函数参数中分配字段。这可以通过运行以下代码来验证:
public class Test {
public static void main(final String[] args) throws Exception {
System.out.println(new Object() {
@Override
public String toString() {
for (Field f : getClass().getDeclaredFields()) {
System.out.println(f.getName());
}
System.out.println(getClass().getDeclaredConstructors()[0].toString());
return "" + args.length;
}
});
}
}
打印:
val$args
Test$1(java.lang.String[])
0
答案 1 :(得分:2)
我认为您需要创建自己的类implements ActionListener
并且具有成员变量来存储列和行值。将构造函数中的列和行值提供给该类。
如上所述,所有单个ActionListener
对象都将从相同的Column
和Row
变量中读取值,因此所有变量最终都将分配给这些变量的最后一个值
答案 2 :(得分:1)
我只是仔细看看你的代码;你怎么能编译这个?您无法访问匿名内部类中的非最终字段(Column, m, n
)。怎么样?
for (int m = 0; m < width; m++)
{
for (int n = 0; n < width; n++)
{
final int innerM = m;
final int innerN = n;
but[m][n].addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
setColumnAndRow(innerM, innerN);
enablenumbers();
disablecolumns();
disablerows();
choose.setText("Now Choose The Nummber You Want To Put In This Square");
}
});
}
}
/*Sets the value of Column and Row when a button is clicked*/
private void setColumnAndRow(int m, int n)
{
Column = m;
Row = n;
}
几点说明:
row
代替Row
和{{1}而不是column
,Column
而不是myVariable
或My_variable
或变体。my_variable
而不是相反)答案 3 :(得分:1)
如果没有看到更多代码,很难说,但看起来你在循环中设置了两个变量Column
和Row
,然后在外面使用它们。如果你只是在循环之外对这些变量做一些事情,那么当你退出时,它们将始终被设置为最大值(因为它只是循环的最后一次迭代将被计算。)
您可能希望直接使用m
方法中的n
和actionPerformed
值,而不是等到循环执行完毕后。或者在ActionListener中定义列或行变量,而不是在外部(否则你最终总是使用相同的值,这些值将是循环中最后声明的值。)