简体   繁体   English

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

[英]Java For Loop - Variable At That Moment - 2D Array Of JButton

I am having a massive issue in the for loop below, I am trying to create action listeners for a series of JButtons, and each JButton has to assign a different value to 'Column' and 'Row', but, for all the buttons 'Column' and 'Row' are only becoming the highest possible value of the for loop, as in if in the for loop m went up to 7, 'Column' would equal 7 for all the buttons, it does not incriment. 我在下面的for循环中遇到了一个大问题,我正在尝试为一系列JButton创建动作监听器,并且每个JButton必须为'Column'和'Row'分配不同的值,但是,对于所有按钮'列'和'行'只是for循环的最高可能值,因为如果在for循环中m达到7,'Column'对于所有按钮将等于7,它不会出现。 In other words, I want the first button 'but[0][0]' to make 'Column' equal to 0, but I also want 'but[1][0]' make 'Column' equal to 1, and so on. 换句话说,我想要第一个按钮'但是[0] [0]'使'Column'等于0,但我也想要'但是[1] [0]'使'Column'等于1,所以上。 Any help would be greatly appreciated. 任何帮助将不胜感激。

The purpose of the buttons is to change the value of 'Column' and 'Row' which are declared elsewhere in the program, so each button needs to make 'Column' and 'Row' equal something different. 按钮的目的是更改在程序中其他位置声明的“列”和“行”的值,因此每个按钮需要使“列”和“行”等于不同的值。

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");
                    }
                }
                );
            }
        }

I guess m and n are declared as fields in the surrounding class (else the ActionListener could not access them, ie there would be a compiler error). 我想mn被声明为周围类中的字段(否则ActionListener无法访问它们,即会出现编译错误)。

The actionPerformed method is invoked when the action is clicked. 单击操作时将调用actionPerformed方法。 At that time, the for loops have completed execution, leaving the maximum column and row numer in the fields m and n . 那时,for循环已经完成执行,在字段mn留下最大的列和行n Put differently, all action listeners access the same m and n , but they should all see different values. 换句话说,所有动作侦听器都访问相同的mn ,但它们都应该看到不同的值。

That already hints at the solution: each ActionListener needs its own variables m and n . 这已经暗示了解决方案:每个ActionListener都需要自己的变量mn In code: 在代码中:

        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");
                }
            }
        );

Note that the variables are declared within the inner for loop; 注意,变量是在内部for循环中声明的; they only exist for a single iteration. 它们只存在于一次迭代中。 Because they are final, they are visible to the anonymous inner class (under the hood, the values of these final variables will be copied into fields of the anonymous class (Evidence for this claim is given in the appendix to this answer) 因为它们是最终的,所以它们对于匿名内部类是可见的(在引擎盖下,这些最终变量的值将被复制到匿名类的字段中(此声明的证据在本答案的附录中给出)

Alternatively, you can take the explicit route and use an inner class: 或者,您可以采用显式路由并使用内部类:

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
}

which you would attach using 您将附加使用

for (m = 0; m < width; m++){
    for (n = 0; n < width; n++){
        but[m][n].addActionListener(new MyActionListener(m,n));
    }
}

Appendix: Implementation of enclosing variable access by inner classes 附录:内部类封闭变量访问的实现

For each final local variable declared in an enclosing scope an inner class accesses, the compiler automatically creates an additional field in the inner class to hold its value, and amends the constructor to assign the field from a new constructor parameter. 对于在内部类访问的封闭范围中声明的每个最终局部变量,编译器会自动在内部类中创建一个附加字段来保存其值,并修改构造函数以从新的构造函数参数中分配字段。 This can be verified by running the following code: 这可以通过运行以下代码来验证:

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;
            }
        });
    }
}

which prints: 打印:

val$args
Test$1(java.lang.String[])
0

I think that you need to create your own class which implements ActionListener and has member variables to store the column and row values. 我认为您需要创建自己的类来implements ActionListener并具有成员变量来存储列和行值。 Supply the column and row values in the constructor to that class. 将构造函数中的列和行值提供给该类。

As written, all of the individual ActionListener objects will be reading the values from the same Column and Row variables and thus all will end up with the last values assigned to those variables 如上所述,所有单个ActionListener对象都将从相同的ColumnRow变量中读取值,因此所有这些对象都将以分配给这些变量的最后值结束

I just took a closer look at your code; 我只是仔细看看你的代码; how are you able to compile this? 你怎么能编译这个? You can't access non-final fields ( Column, m, n )inside of the anonymous-inner class like that. 您无法访问匿名内部类中的非最终字段( Column, m, n )。 How about this? 这个怎么样?

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

A couple of notes: 几个笔记:

  • On your variable names - in Java it's convention to begin variable names with lower case letters and camel-case words so row instead of Row and column instead of Column , myVariable instead of My_variable or my_variable or variations. 在您的变量名称上 - 在Java中,通常使用小写字母和驼峰式单词开始变量名称,因此row而不是Rowcolumn而不是ColumnmyVariable而不是My_variablemy_variable或变体。
  • On rows vs. columns - Java (and most other languages that derive syntax from C) have 0-based two-dimensional arrays where the first index selects the row and the second selects the column. 在行与列上 - Java(以及从C派生语法的大多数其他语言)具有基于0的二维数组,其中第一个索引选择行,第二个索引选择列。 I'm not sure what your purpose is but you might find that others get confused by your switching of the two indexes (ie I'd expect arr[row][col] not the other way around) 我不确定你的目的是什么,但你可能会发现其他人因你切换两个索引而感到困惑(也就是说,我希望arr[row][col]不是相反的方式)

It's difficult to say without seeing more code, but it looks like you're setting two variables Column and Row within the loop, then using them outside. 如果没有看到更多的代码,很难说,但看起来你在循环中设置了两个变量ColumnRow ,然后在外面使用它们。 If you're just doing something with those variables outside the loop, then by the time you exit they'll always be set to the maximum values (because it's only the last iteration of the loop that will count.) 如果你只是在循环之外对这些变量做一些事情,那么当你退出它们时,它们总是被设置为最大值(因为它只是循环的最后一次迭代将被计算。)

You probably want to use the m and n values inside the actionPerformed method directly rather than waiting until after the loop has executed. 您可能希望直接在actionPerformed方法中使用mn值,而不是等到循环执行完之后。 Either that or define column and row variables within your ActionListener, not outside (otherwise you'll just end up always using the same values which will be the ones declared last in the loop.) 或者在ActionListener中定义列或行变量,而不是在外部(否则你最终总是使用相同的值,这些值将是循环中最后声明的值。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM