Справка KeyEvent Handler - JAVA [дубликат]

Вот пример, чтобы добавить к тому, что уже написано другими. Предположим, вы хотите создать массив функций adderFunctions, где каждая функция принимает один аргумент Number и возвращает сумму аргумента и индекс функции в массиве. Попытка сгенерировать adderFunctions с помощью цикла с использованием ключевого слова var не будет работать так, как можно было бы наивно ожидать:

// An array of adder functions.
var adderFunctions = [];

for (var i = 0; i < 1000; i++) {
  // We want the function at index i to add the index to its argument.
  adderFunctions[i] = function(x) {
    // What is i bound to here?
    return x + i;
  };
}

var add12 = adderFunctions[12];

// Uh oh. The function is bound to i in the outer scope, which is currently 1000.
console.log(add12(8) === 20); // => false
console.log(add12(8) === 1008); // => true
console.log(i); // => 1000

// It gets worse.
i = -8;
console.log(add12(8) === 0); // => true

. Вышеописанный процесс не генерирует желаемый массив функций, потому что i выходит за пределы итерации блока for, в котором была создана каждая функция. Вместо этого в конце цикла i в закрытии каждой функции ссылается на значение i в конце цикла (1000) для каждой анонимной функции в adderFunctions. Это совсем не то, чего мы хотели: теперь у нас есть массив из 1000 различных функций в памяти с точно таким же поведением. И если мы впоследствии обновим значение i, мутация повлияет на все adderFunctions.

Однако мы можем попробовать снова, используя ключевое слово let:

// Let's try this again.
// NOTE: We're using another ES6 keyword, const, for values that won't
// be reassigned. const and let have similar scoping behavior.
const adderFunctions = [];

for (let i = 0; i < 1000; i++) {
  // NOTE: We're using the newer arrow function syntax this time, but 
  // using the "function(x) { ..." syntax from the previous example 
  // here would not change the behavior shown.
  adderFunctions[i] = x => x + i;
}

const add12 = adderFunctions[12];

// Yay! The behavior is as expected. 
console.log(add12(8) === 20); // => true

// i's scope doesn't extend outside the for loop.
console.log(i); // => ReferenceError: i is not defined

На этот раз i отскок на каждой итерации цикла for. Каждая функция теперь сохраняет значение i во время создания функции, а adderFunctions ведет себя так, как ожидалось.

Теперь изображение смешивает два поведения, и вы, вероятно, увидите, почему это не рекомендуется для смешивания новых let и const со старым var в том же скрипте. Это может привести к некоторому эффектно запутанному коду.

const doubleAdderFunctions = [];

for (var i = 0; i < 1000; i++) {
    const j = i;
    doubleAdderFunctions[i] = x => x + i + j;
}

const add18 = doubleAdderFunctions[9];
const add24 = doubleAdderFunctions[12];

// It's not fun debugging situations like this, especially when the
// code is more complex than in this example.
console.log(add18(24) === 42); // => false
console.log(add24(18) === 42); // => false
console.log(add18(24) === add24(18)); // => false
console.log(add18(24) === 2018); // => false
console.log(add24(18) === 2018); // => false
console.log(add18(24) === 1033); // => true
console.log(add24(18) === 1030); // => true

Не позволяйте этому случиться с вами. Используйте linter.

ПРИМЕЧАНИЕ. Это пример обучения, предназначенный для демонстрации поведения var / let в циклах и закрытия функций, которые также будут легко понятны. Это был бы ужасный способ добавить числа. Но общая техника захвата данных при закрытии анонимных функций может встречаться в реальном мире в других контекстах. YMMV.

0
задан mKorbel 18 June 2015 в 11:11
поделиться

2 ответа

Моя цель здесь - создать массив JTextFields, в котором есть keylistener. Этот keylistener должен помещать в JTextField

ничего, кроме чисел, которые должны быть введены). Короткий ответ, таким образом, не используется KeyListener, он не будет фиксировать варианты использования пользователя вставка текста в поле или если поле обновляется программно

Вместо этого вы хотите использовать DocumentFilter, например

public class IntFilter extends DocumentFilter {

    @Override
    public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {

        StringBuilder buffer = new StringBuilder(text.length());
        for (int index = 0; index < text.length(); index++) {
            if (Character.isDigit(text.charAt(index))) {
                buffer.append(text.charAt(index));
            }
        }
        super.insertString(fb, offset, buffer.toString(), attr);
        ValidationListener listener = getValidationListener();
    }

    @Override
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException {
        if (length > 0) {
            fb.remove(offset, length);
        }
        insertString(fb, offset, string, attr);
    }
}

См. Реализация фильтра документов для более подробной информации и Примеры DocumentFilter для других примеров

Также следует изменить цвет фона JTextField, если введенный номер не является int

Вы можете выполнить проверку по почте с помощью InputVerifier, но это может не соответствовать вашим потребностям.

Это создает проблему. DocumentFilter, не должен заботиться о поле, к которому он применяется, но поскольку он выполняет проверку, он будет знать, когда что-то пошло не так, поэтому нам нужно, чтобы фильтр предоставлял уведомление, когда проверка не удалась. .

Во-первых, нам нужен какой-то обратный вызов, который говорит нам, когда проверка не прошла или прошла ...

public interface ValidationListener {

    public void validationFailed();

    public void validationPassed();
}

Затем нам нужно обновить фильтр, чтобы поднять эти уведомления на основе его правила ...

public class IntFilter extends DocumentFilter {

    private ValidationListener validationListener;

    public void setValidationListener(ValidationListener validationListener) {
        this.validationListener = validationListener;
    }

    public ValidationListener getValidationListener() {
        return validationListener;
    }

    @Override
    public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {

        boolean validationFailed = false;
        StringBuilder buffer = new StringBuilder(text.length());
        for (int index = 0; index < text.length(); index++) {
            if (Character.isDigit(text.charAt(index))) {
                buffer.append(text.charAt(index));
            } else {
                validationFailed = true;
            }
        }
        super.insertString(fb, offset, buffer.toString(), attr);
        ValidationListener listener = getValidationListener();
        if (listener != null) {
            if (validationFailed) {
                listener.validationFailed();
            } else {
                listener.validationPassed();
            }
        }
    }

    @Override
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException {
        if (length > 0) {
            fb.remove(offset, length);
        }
        insertString(fb, offset, string, attr);
    }
}

Затем нам нужно определить нашу реализацию ValidationListener для выполнения необходимых действий ...

public class DefaultValidationHandler implements ValidationListener {

    private JTextField field;

    public DefaultValidationHandler(JTextField field) {
        this.field = field;
    }

    public JTextField getField() {
        return field;
    }

    @Override
    public void validationFailed() {
        getField().setBackground(Color.RED);
    }

    @Override
    public void validationPassed() {
        getField().setBackground(UIManager.getColor("TextField.background"));
    }

}

Здесь слушатель поддерживает ссылка на поле, которое мы хотим контролировать

. Затем мы связываем его вообще ...

JTextField field = new JTextField(10);
DefaultValidationHandler handler = new DefaultValidationHandler(field);
IntFilter filter = new IntFilter();
filter.setValidationListener(handler);
((AbstractDocument)field.getDocument()).setDocumentFilter(filter);

Filter [/g5]

Это [20] Некоторые улучшения могут включать передачу ссылки DocumentFilter назад с помощью методов ValidationListener, вы можете использовать это для поиска поле, которое вызвало событие и обновило его, уменьшив количество обработчиков, ght необходимо создать, например.

Например

Обновлен ValidationListener

public interface ValidationListener {

    public void validationFailed(DocumentFilter filter);

    public void validationPassed(DocumentFilter filter);
}

Обновлен IntFilter

public class IntFilter extends DocumentFilter {

    private ValidationListener validationListener;

    public void setValidationListener(ValidationListener validationListener) {
        this.validationListener = validationListener;
    }

    public ValidationListener getValidationListener() {
        return validationListener;
    }

    @Override
    public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {

        boolean validationFailed = false;
        StringBuilder buffer = new StringBuilder(text.length());
        for (int index = 0; index < text.length(); index++) {
            if (Character.isDigit(text.charAt(index))) {
                buffer.append(text.charAt(index));
            } else {
                validationFailed = true;
            }
        }
        super.insertString(fb, offset, buffer.toString(), attr);
        ValidationListener listener = getValidationListener();
        if (listener != null) {
            if (validationFailed) {
                listener.validationFailed(this);
            } else {
                listener.validationPassed(this);
            }
        }
    }

    @Override
    public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String string, AttributeSet attr) throws BadLocationException {
        if (length > 0) {
            fb.remove(offset, length);
        }
        insertString(fb, offset, string, attr);
    }
}

Пример реализации ...

public class TestPane extends JPanel {

    private Map<DocumentFilter, JTextField> fields;

    public TestPane() {

        fields = new HashMap<>(25);
        ValidationListener listener = new ValidationListener() {

            @Override
            public void validationFailed(DocumentFilter filter) {
                JTextField field = fields.get(filter);
                if (field != null) {
                    field.setBackground(Color.RED);
                }
            }

            @Override
            public void validationPassed(DocumentFilter filter) {
                JTextField field = fields.get(filter);
                if (field != null) {
                    field.setBackground(UIManager.getColor("TextField.background"));
                }
            }
        };

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        for (int index = 0; index < 10; index++) {
            JTextField field = new JTextField(10);
            IntFilter filter = new IntFilter();
            filter.setValidationListener(listener);
            ((AbstractDocument) field.getDocument()).setDocumentFilter(filter);
            fields.put(filter, field);
            add(field, gbc);
        }

    }

}
4
ответ дан MadProgrammer 26 August 2018 в 22:56
поделиться

У вас проблема с определением области охвата, поэтому получение этой ошибки:

for(int i = 0; i<nextTextBox;i++) //you are declaring i here

с использованием внутри KeyListener. Это запрещено. Поскольку доступ к переменной local non-final недоступен из внутреннего класса для доступа, он должен быть окончательным. В вашем случае я не думаю, что можно сделать i final

Итак, одно быстрое исправление объявляет i в области класса с помощью JFrame и JPanel

JFrame myMainWindow = new JFrame("Sorts");

JPanel sortPanel = new JPanel();
int i; 

, тогда используйте его где угодно

 for(i = 0; i<nextTextBox;i++)
0
ответ дан Saif 26 August 2018 в 22:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: