Java For Loop - 当时的变量 - JButton的2D数组

时间:2011-03-13 00:54:00

标签: java multidimensional-array for-loop 2d jbutton

我在下面的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");
                    }
                }
                );
            }
        }

4 个答案:

答案 0 :(得分:4)

我猜mn被声明为周围类中的字段(否则ActionListener无法访问它们,即会出现编译错误。)

单击操作时将调用actionPerformed方法。那时,for循环已完成执行,在字段mn中保留最大列和行数。换句话说,所有动作侦听器都访问相同的mn,但它们都应该看到不同的值。

这已经暗示了解决方案:每个ActionListener都需要自己的变量mn。在代码中:

        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对象都将从相同的ColumnRow变量中读取值,因此所有变量最终都将分配给这些变量的最后一个值

答案 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; 
}

几点说明:

  • 在您的变量名称上 - 在Java中,通常使用小写字母和驼峰式单词开始变量名称,因此row代替Row和{{1}而不是columnColumn而不是myVariableMy_variable或变体。
  • 在行与列 - Java(以及从C派生语法的大多数其他语言)具有基于0的二维数组,其中第一个索引选择行,第二个索引选择列。我不确定你的目的是什么,但你可能会发现其他人因你转换这两个索引而感到困惑(即我期望my_variable而不是相反)

答案 3 :(得分:1)

如果没有看到更多代码,很难说,但看起来你在循环中设置了两个变量ColumnRow,然后在外面使用它们。如果你只是在循环之外对这些变量做一些事情,那么当你退出时,它们将始终被设置为最大值(因为它只是循环的最后一次迭代将被计算。)

您可能希望直接使用m方法中的nactionPerformed值,而不是等到循环执行完毕后。或者在ActionListener中定义列或行变量,而不是在外部(否则你最终总是使用相同的值,这些值将是循环中最后声明的值。)