-1

I have hard time finding any guides on how to addEventHandlerfor textfield so that it does real time validation from key inputs to only allow hh:mm time format. I found this expression ^([0-9]|0[0-9]|1[0-9]|2[0-3]):[0-5][0-9]$ but don't know how to add it to the eventHandler. Also I was trying to use simpleDateFormat but with no success.

Edit: I'm trying to to make something like this (this was with JFrame):

JTextField iegadesVerTesksts = new JTextField();
panel.add(iegadesVerTesksts);
iegadesVerTesksts.addKeyListener(new KeyAdapter() {
        public void keyTyped(KeyEvent evt) {
            char c = evt.getKeyChar();
            if ((!(Character.isDigit(c) || (c == KeyEvent.VK_BACK_SPACE) || c == KeyEvent.VK_DELETE))
                    &&evt.getKeyChar()!='.') {
                evt.consume();
            }
            if(evt.getKeyChar()=='.'&&iegadesVerTesksts.getText().contains(".")){
                evt.consume();
            }
        }
    });

Right now with JavaFX I have created main and piezimes.java. In product class I define objects I want to create:

public class Piezimes {
private LocalDate datums;
private String laiks;
private String piezime;

public Piezimes(){
    this.datums = null;
    this.laiks = "";
    this.piezime = "";
}

public Piezimes (LocalDate datums, String laiks, String piezime ){
    this.datums = datums;
    this.laiks = laiks;
    this.piezime = piezime;
}

public LocalDate getDatums() {

    return datums;
}

public void setDatums(LocalDate datums) {

    this.datums = datums;
}

public String getLaiks() {

    return laiks;
}

public void setLaiks(String laiks) {
    this.laiks = laiks;
}

public String getPiezime() {

    return piezime;
}

public void setPiezime(String piezime) {

    this.piezime = piezime;
}

}

And In main.java I have created tableView where at the end I added buttons where I call .getText so I can user input. Only with time validation I have problems with. Method right now that I call to add user input to table is: piezimes.setLaiks(laiksIevade.getText());

Mārtiņš Ciekurs
  • 437
  • 1
  • 6
  • 25
  • https://stackoverflow.com/questions/31039449/java-8-u40-textformatter-javafx-to-restrict-user-input-only-for-decimal-number https://stackoverflow.com/a/12851162/2189127 – James_D Oct 01 '17 at 17:20
  • @James_D tried both. Doesn't work for my program... – Mārtiņš Ciekurs Oct 01 '17 at 18:04
  • You should rewrite your question to show what you tried and explain in what way it doesn't work. Provide a [MCVE]. The linked questions provide the correct way to do this. – James_D Oct 01 '17 at 18:14
  • Just wondering what you do in your swing application t prevent the user pasting invalid text with the mouse (right-click, paste, etc)? Where is the code where you tried the solutions in the linked questions? – James_D Oct 01 '17 at 18:37
  • @James_ I added validation right after creating `textfield` . So code was something like this. `laiksIevade.textProperty().addListener(new ChangeListener() {...`. And than I just called `piezimes.setLaiks(laiksIevade.getText());` to get user input and done. I guess I did it totally wrong. – Mārtiņš Ciekurs Oct 01 '17 at 18:56
  • So why don't you try the solutions I linked? With the `TextFormatter` – James_D Oct 01 '17 at 18:57
  • @James_D Tried variation with `TextFormatter`. It does't want to do any validation at user input. Probl. i'm I shouldn't use value from `textField` as `String`. But I tried with `double` also and it didn't change the result. Here is pastebin to my code if that helps. [main.java](https://pastebin.com/CWEcRQPr) [piezimes.java](https://pastebin.com/ZvNLYjNj) – Mārtiņš Ciekurs Oct 01 '17 at 19:25

1 Answers1

-1

To be honest I am not very familiar with TextFormatter. Every time I want to do something like this I am doing a custom TextField in which I add a changeListener to the textProperty and check the user's input matches a regex. Now in your situation you will need to add at least one more to the focusedProperty in order to check if the user left the input incomplete and I would recommend to add one more to catch action events. Now I am not a master with regular expressions so be lenient xD. Here is my implementation :

class CustomField extends TextField {

        public CustomField() {
            super();
            textProperty().addListener(new ChangeListener<String>() {
                @Override
                public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                    if (newValue.isEmpty())
                        return;

                    if (newValue.matches("\\d{1,2}|\\d{1,2}:|\\d{1,2}:[0-5]?[0-9]")) {
                        setText(newValue);
                    } else {
                        setText(oldValue);
                    }
                }
            });

            setOnAction(e -> {
                if (!getText().matches("\\d{2}:\\d{2}")) {
                    setText("");
                }
            });

            focusedProperty().addListener(new ChangeListener<Boolean>() {
                @Override
                public void changed(ObservableValue<? extends Boolean> arg0, Boolean oldPropertyValue,
                        Boolean newPropertyValue) {
                    if (!newPropertyValue) {
                        if (!getText().matches("\\d{2}:\\d{2}")) {
                            setText("");
                        }
                    }
                }
            });
        }
    }

While the user write something to the textField all you need to do is to check if it matches the NN:XN (N = number 0-9 & X = number 0-5 ) or just a portion of it. When the input is finished you will check if it matches to your format and only then you will let it be, otherwise set the textfield content to "".

Of course I am not saying this is the right way or at the best one, but it's a 'workaround' for people like me who don't know about the TextFormatter :P

JKostikiadis
  • 2,847
  • 2
  • 22
  • 34
  • I don't want to ask a stupid question but how exactly do I call it for my `textField`? I created class and new object which is `CustomField c1 = new CustomField();`. But what to do next?.. Really new to programming, btw... – Mārtiņš Ciekurs Oct 01 '17 at 20:34
  • Nothing :P just add the c1 node to stage and it will only accept inputs with your desire format ( If i understand you correct ofc ) – JKostikiadis Oct 01 '17 at 20:40
  • Ok, I found a problem. I'm an idiot. I was calling validation in my void method all the time but not in the `void start`. That's why every time when I was trying to put any text validation in, it wouldn't work. Now it works perfectly fine. Btw, thanks a lot for answer. – Mārtiņš Ciekurs Oct 01 '17 at 20:47
  • 1
    The one problem with this approach, in which you observe changes to the text and revert them if they are invalid, is that if you have other listeners on the text property, they will also see the invalid state before they see the valid state. So any other listeners have to know to check for a valid state of the text (and probably ignore it if it is invalid). The `TextFormatter` avoids this by effectively vetoing text changes before they occur. It also has a `value` property which contains the committed value from the user, which can be any type and you can implement any parsing logic you need. – James_D Oct 01 '17 at 20:56
  • Yeah I knew that having other listener will cause 'problems' if you don't ignore the invalid input, which you can handle easy but i wasn't aware about the TextFormatter capabilities to be honest. I am going to check it right away. – JKostikiadis Oct 01 '17 at 21:01