Вот пример, чтобы добавить к тому, что уже написано другими. Предположим, вы хотите создать массив функций 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.
ПРИМЕЧАНИЕ. Это пример обучения, предназначенный для демонстрации поведения
blockquote>var
/let
в циклах и закрытия функций, которые также будут легко понятны. Это был бы ужасный способ добавить числа. Но общая техника захвата данных при закрытии анонимных функций может встречаться в реальном мире в других контекстах. YMMV.
Моя цель здесь - создать массив JTextFields, в котором есть keylistener. Этот keylistener должен помещать в JTextField
blockquote>ничего, кроме чисел, которые должны быть введены). Короткий ответ, таким образом, не используется
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
blockquote>Вы можете выполнить проверку по почте с помощью
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);
[/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); } } }
У вас проблема с определением области охвата, поэтому получение этой ошибки:
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++)