Java для цикла - переменная в данный момент - 2D массив JButton - PullRequest
2 голосов
/ 13 марта 2011

У меня есть серьезная проблема в цикле for ниже, я пытаюсь создать слушателей действия для серии JButton, и каждый JButton должен назначить различное значение для 'Column' и 'Row', но для всехКнопки «Столбец» и «Строка» становятся только максимально возможными значениями цикла for, так как если бы в цикле «m» поднялось до 7, «Столбец» для всех кнопок равнялся бы 7, это не является инкриментом.Другими словами, я хочу, чтобы первая кнопка «но [0] [0]» делала «Столбец» равным 0, но я также хочу, чтобы «но [1] [0]» делала «Столбец» равным 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 ]

4 голосов
/ 13 марта 2011

Полагаю, 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
2 голосов
/ 13 марта 2011

Я думаю, что вам нужно создать свой собственный класс, который implements ActionListener и имеет переменные-члены для хранения значений столбца и строки. Укажите значения столбца и строки в конструкторе для этого класса.

Как написано, все отдельные ActionListener объекты будут считывать значения из одинаковых переменных Column и Row и, таким образом, все получат последние значения, присвоенные этим переменным

1 голос
/ 13 марта 2011

Трудно сказать, не видя больше кода, но похоже, что вы устанавливаете две переменные Column и Row в цикле, а затем используете их снаружи.Если вы просто что-то делаете с этими переменными вне цикла, то к моменту выхода из них они всегда будут установлены на максимальные значения (поскольку будет учитываться только последняя итерация цикла).

Возможно, вы хотите использовать значения m и n внутри метода actionPerformed напрямую, а не ждать, пока цикл не будет выполнен.Либо так, либо определите переменные столбца и строки в ActionListener, а не снаружи (в противном случае вы просто всегда будете использовать одни и те же значения, которые будут объявлены последними в цикле.)

1 голос
/ 13 марта 2011

Я просто внимательно посмотрел на ваш код; как вы можете скомпилировать это? Вы не можете получить доступ к неконечным полям (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 и column вместо Column, myVariable вместо My_variable или my_variable или вариантов.
  • По строкам и столбцам - Java (и большинство других языков, которые получают синтаксис из C) имеют двумерные массивы на основе 0, где первый индекс выбирает строку, а второй - столбец. Я не уверен, какова ваша цель, но вы можете обнаружить, что другие смущаются при переключении двух индексов (то есть я бы ожидал, что arr[row][col] не наоборот)
...