Как ограничить выход записи за пределы TextField в JavaFX?

Делаю "Сканворд" - приложение с помощью JavaFX. Создал GridPane в программе scenebuilder и не понимаю как сделать так, чтобы при записи в textfield слова не налезали на решётку. Необходимо, чтобы каждая буква была в своем квадрате.


Ответы (2 шт):

Автор решения: Давид Манжула

Я так понял, вам нужно чтоб одной клетке была только одна буква.

Сразу предупрежу, я не Java-разработчик, но постараюсь объяснить.

Во-первых, на каждую клетку должно быть свое текстовое поле. Если фреймворк позволяет добавлять элементы динамически, рекомендую создать двухмерный массив и циклом создавать поля и автоматически подставлять размеры и позицию.

Полю нужно задать ограничение на макс длину в 1 символ. И после ввода символа переводить фокус на следующий элемент.

Ниже представлен примен на JavaScript, не пытайтесь просто переписать код на Java, лучше поймите алгоритм и суть и напишите свою реализацию.

var elements = [];

for (let i = 0; i < 5; i++) {
  // Создаем элемент
  let input = document.createElement("input");
  // Задаем длину
  input.maxLength = 1;
  // Слушаем событие ввода
  input.addEventListener("keyup", function(event) {
    // Следующим будет клетка правее
    let next = 1;
    // Но если мы только что стерли символ - нужно выбрать левее
    if (input.value.length == 0) {
      next = -1;
    }

    let index = i + next;
    // Если такой есть - выбираем его
    if (elements[index]) {
      elements[index].focus();
      elements[index].select();
    }
  });
  // Добавляем в массив. Можно тут же добавлять на страницу, но в массив нужно, чтоб потом можно было сфокусировать предыдущий/следующий
  elements.push(input);
}

for (var i = 0; i < elements.length; i++) {
  let element = elements[i];
  element.style.left = (i * 24) + "px"; // задаем позицию
  document.body.appendChild(element);
}
input {
  position: absolute;
  top: 0;
  display: inline-block;
  width: 24px;
  height: 24px;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

→ Ссылка
Автор решения: Слава

Моё решение стало таковым: Так как я не создавал элементы динамически, пришлось импровизировать и писать такой код:

    //Форматтер на заглавные буквы + Лимитер(макс. длина)
    Pattern pattern = Pattern.compile(".{0,1}");
            TextField[] textik = {TF_7_3, TF_7_4, TF_7_5, TF_7_6...};
            List<TextField> textFields = new ArrayList<>();
            textFields = Arrays.asList(textik);
    
            for (TextField tf : textFields) {
                tf.setTextFormatter(new TextFormatter<>(change -> {
                    change.setText(change.getText().toUpperCase());
                    return pattern.matcher(change.getControlNewText()).matches() ? change : null;
                }));
            }

В этом коде, я реализовал лимит + uppercase, далее пришлось инициализировать управление:

                TF_9_4.setOnKeyReleased(keyEvent -> {
                    if (TF_9_4.getText().length() == 1) {
                        TF_9_5.requestFocus();
                    }
                });
                TF_9_5.setOnKeyReleased(keyEvent -> {
                    if (TF_9_5.getText().length() == 1) {
                        TF_9_6.requestFocus();
                    } else if (TF_9_5.getText().trim().isEmpty()) {
                        TF_9_4.requestFocus();
                    }
                });
                TF_9_6.setOnKeyReleased(keyEvent -> {
                    if (TF_9_6.getText().length() == 1) {
                        TF_9_7.requestFocus();
                    } else if (TF_9_6.getText().trim().isEmpty()) {
                        TF_9_5.requestFocus();
                    }
                });
                TF_9_7.setOnKeyReleased(keyEvent -> {
                    if (TF_9_7.getText().trim().isEmpty()) {
                        TF_9_6.requestFocus();
                    }
                });

Это селектер. Как только в TextField будет 1 символ, пользователя переключит на другой TextField + если он пуст, возвращает назад.

→ Ссылка