Help me to understand. I wrote a simple calculator on java + javaFX. The whole application here is bitbucket . When writing, I tried to implement the MVC pattern.

The structure is as follows: class Executor - application launch; class Controller - handling keystrokes, class Calculator - performing calculations, inerface Display , user interface implemented separately - ui.fxml

The question is - where is it better (CORRECT) to implement validation of user-entered values ​​(prohibit typing letters from the keyboard) in a separate class or method? If in the method, in which of the listed classes is this method better implemented (Google did not help, gives examples where everything is implemented in the Main class and the buttons, and the test and start of the application, and a whole lot more). Purely intuitive, I want to do validation in a separate class, but I don’t have enough skill to link this whole thing to a display field of type TextField

class Controller { @FXML private TextField display; //TODO } 

ui.fxml string

 <TextField fx:id="display" styleClass="display" ......... > 

I understand that I need a regular method that checks (limits) user input of data and further declares an instance of the validation class in the Controller , but I don’t attach my mind to the display field.

Or am I too smart with this whole thing?

    2 answers 2

    Wah, wah, I did it. Everything is solved much easier. And it is decided exactly as I had to. So, in order.

    To implement the restriction of user-entered data from the keyboard, you must: write a class that performs this very check, and as Yuri_Prime said, this class must extend the TextField class. I give my class as an example.

     package com.javaFX.calculator.validationOfData; import javafx.scene.control.TextField; public class CalcWindowTxtFld extends TextField { public CalcWindowTxtFld() { } @Override public void replaceText(int start, int end, String text) { if (text.matches("[ ]") || text.isEmpty()) { super.replaceText(start, end, text); } } @Override public void replaceSelection(String replacement) { super.replaceSelection(replacement); } } 

    Next, go to the fxml file, register the import of our Validator class, like this:

     <?import com.javaFX.calculator.validationOfData.CalcWindowTxtFld ?> 

    And the final step is changing the type of the required TextField field to a custom one, in my case CalcWindowTxtFld . Should have the following. It was

     <TextField fx:id="display" styleClass="display" ......... > 

    has become

     <CalcWindowTxtFld fx:id="display" styleClass="display" ......... > 

    It should be noted that in Controller there is no need to change the field type from TextField to CalcWindowTxtFld . Playing regular games you can achieve the desired result.

    Special thanks I want to express Yuri_Prime for help and tips.

      When I did data validation to limit the input data, I inherited TextField and in it overridden the replaceText () method. This allowed not only to restrict the data after entering, but also to restrict the entered characters - with the correct regexp it will be impossible to enter letters where only numbers are needed. A class was also written to control validation, the object of which was specified as property. At the output, the validator gave BooleanProperty, which allowed you to directly block interface objects. Total: two classes and some witchcraft with property. It seems to me the best option.

      The code of the modified TextField looks like this:

       private final ObjectProperty<ValidationChecker> onValidate = new SimpleObjectProperty<>(this, "onValidate", null); private final ObjectProperty<Predicate<String>> symbolsChecker = new SimpleObjectProperty<>(this, "symbolsChecker", null); private final ObjectProperty<Predicate<String>> textChecker = new SimpleObjectProperty<>(this, "textChecker", null); @Override public void replaceText(int start, int end, String text){ if(this.getSymbolsChecker() == null || this.getTextChecker() == null){ //Если не определеные функции проверки символов или текста //вести себя как обычное текстовое поле super.replaceText(start, end, text); return; } if(this.getSymbolsChecker().test(text)) { //Если введённый текст/символы проходят проверку //Добавляем его к уже имеющемуся тексту //symbolstChecker ограничивает вводимые символы super.replaceText(start, end, text); } if(this.getTextChecker().test(this.getText())) { //Если полный текст поля проходит проверку //Уведомляем валидатор, что всё хорошо Platform.runLater(() -> this.getOnValidate().handle(new ValidationUpdateEvent(this.getId(), true))); } else { //Иначе, уведомляем о том, что всё плохо и //какой-то контрол стоит заблокировать Platform.runLater(() -> this.getOnValidate().handle(new ValidationUpdateEvent(this.getId(), false))); } } 

      A little bit of explanation to the code above. symbolsChecker and textChecker are objects that implement the Predicate <String> interface, which decide whether the entered text will be added to the text field (symbolsChecker) and whether all text in the text field (textChecker) will be validated. Two checks were used because in my task it was necessary to limit the input only to numbers and plus limit the range of numbers entered. They are made through property so that you can specify them not in the code, but through the FXML file.

      The validator code is extremely simple:

       public class ValidationChecker implements EventHandler<ValidationUpdateEvent> private HashMap<String, Boolean> validationInfo = new HashMap<>(); private BooleanProperty isValid = new SimpleBooleanProperty(this, "isValid", true); @Override public void handle(ValidationUpdateEvent event) { this.validationInfo.put(event.getID(), event.isValid()); if(this.validationInfo.containsValue(false)){ this.isValid.set(false); } else{ this.isValid.set(true); } } 

      Again a bit of explanation. Each TextField has a text property ID. When attempting to enter data in a text field, a validator will be notified, which will register in HashMap the current value of the validity of the field with the specified ID. In this validator, a logical AND is implemented: if at least in one text field associated with the validator the data is not valid, then the isValid property will be false, and the control that has the disable property on the isValid validator will be blocked.

      • Thanks for the answer. I vaguely imagine the implementation of this business, but I will try. - Denis N
      • If necessary, I can roughly paint it, as I have implemented it - Yuri_Prime
      • Oh, I will be very grateful to you. - Denis N
      • Updated the answer, look - Yuri_Prime
      • Thank you for such a detailed response. Tomorrow I will try to fasten it to my application and accomplish the results. - Denis N