Time Mask or TimePicker JavaFX

6

I have TextField where I enter the time, however I always have to type : . How can I put a mask in this TextField or if it is simpler a TimePicker ?

    
asked by anonymous 29.07.2015 / 14:14

2 answers

1

here in this site link has a solution, but the best thing would be to create a skin.

import java.util.regex.Pattern;  

import javafx.application.Application;  
import javafx.beans.binding.Bindings;  
import javafx.beans.binding.IntegerBinding;  
import javafx.beans.property.ReadOnlyIntegerProperty;  
import javafx.beans.property.ReadOnlyIntegerWrapper;  
import javafx.geometry.Insets;  
import javafx.scene.Scene;  
import javafx.scene.control.IndexRange;  
import javafx.scene.control.Label;  
import javafx.scene.control.TextField;  
import javafx.scene.layout.VBox;  
import javafx.stage.Stage;  

public class TimeTextFieldTest extends Application {  

 @Override  
  public void start(Stage primaryStage) {  
  VBox root = new VBox(5);  
  root.setPadding(new Insets(5));  
  Label hrLabel = new Label();  
  Label minLabel = new Label();  
  Label secLabel = new Label();  
  TimeTextField timeTextField = new TimeTextField();  
  hrLabel.textProperty().bind(Bindings.format("Hours: %d", timeTextField.hoursProperty()));  
  minLabel.textProperty().bind(Bindings.format("Minutes: %d", timeTextField.minutesProperty()));  
  secLabel.textProperty().bind(Bindings.format("Seconds: %d", timeTextField.secondsProperty()));  

  root.getChildren().addAll(timeTextField, hrLabel, minLabel, secLabel);  
  Scene scene = new Scene(root);  
  primaryStage.setScene(scene);  
  primaryStage.show();  
  }  

  public static void main(String[] args) {  
  launch(args);  

  }  

  public static class TimeTextField extends TextField {  

    enum Unit {HOURS, MINUTES, SECONDS};  

    private final Pattern timePattern ;  
    private final ReadOnlyIntegerWrapper hours ;  
    private final ReadOnlyIntegerWrapper minutes ;  
    private final ReadOnlyIntegerWrapper seconds ;  

    public TimeTextField() {  
      this("00:00:00");  
    }  
    public TimeTextField(String time) {  
      super(time);  
      timePattern = Pattern.compile("\d\d:\d\d:\d\d");  
      if (! validate(time)) {  
        throw new IllegalArgumentException("Invalid time: "+time);  
      }  
      hours = new ReadOnlyIntegerWrapper(this, "hours");  
      minutes = new ReadOnlyIntegerWrapper(this, "minutes");  
      seconds = new ReadOnlyIntegerWrapper(this, "seconds");  
      hours.bind(new TimeTextField.TimeUnitBinding(Unit.HOURS));  
      minutes.bind(new TimeTextField.TimeUnitBinding(Unit.MINUTES));  
      seconds.bind(new TimeTextField.TimeUnitBinding(Unit.SECONDS));  
    }  

    public ReadOnlyIntegerProperty hoursProperty() {  
      return hours.getReadOnlyProperty();  
    }  

    public int getHours() {  
      return hours.get() ;  
    }  

    public ReadOnlyIntegerProperty minutesProperty() {  
      return minutes.getReadOnlyProperty();  
    }  

    public int getMinutes() {  
      return minutes.get();  
    }  

    public ReadOnlyIntegerProperty secondsProperty() {  
      return seconds.getReadOnlyProperty();  
    }  

    public int getSeconds() {  
      return seconds.get();  
    }  

    @Override  
    public void appendText(String text) {  
      // Ignore this. Our text is always 8 characters long, we cannot append anything  
    }  

    @Override  
    public boolean deleteNextChar() {  

      boolean success = false ;  

      // If there's a selection, delete it:  
      final IndexRange selection = getSelection();  
      if (selection.getLength()>0) {  
        int selectionEnd = selection.getEnd();  
        this.deleteText(selection);  
        this.positionCaret(selectionEnd);  
        success = true ;  
      } else {  
        // If the caret preceeds a digit, replace that digit with a zero and move the caret forward. Else just move the caret forward.  
      int caret = this.getCaretPosition();  
      if (caret % 3 != 2) { // not preceeding a colon  
        String currentText = this.getText();  
        setText(currentText.substring(0, caret) + "0" + currentText.substring(caret+1));  
        success = true ;  
      }  
      this.positionCaret(Math.min(caret+1, this.getText().length()));  
      }  
      return success ;  
    }  

    @Override  
    public boolean deletePreviousChar() {  

      boolean success = false ;  

      // If there's a selection, delete it:  
      final IndexRange selection = getSelection();  
      if (selection.getLength()>0) {  
        int selectionStart = selection.getStart();  
        this.deleteText(selection);  
        this.positionCaret(selectionStart);  
        success = true ;  
      } else {  
      // If the caret is after a digit, replace that digit with a zero and move the caret backward. Else just move the caret back.  
        int caret = this.getCaretPosition();  
        if (caret % 3 != 0) { // not following a colon  
          String currentText = this.getText();  
          setText(currentText.substring(0, caret-1) + "0" + currentText.substring(caret));  
          success = true ;  
        }  
        this.positionCaret(Math.max(caret-1, 0));  
      }  
      return success ;  
    }  

    @Override  
    public void deleteText(IndexRange range) {  
      this.deleteText(range.getStart(), range.getEnd());  
    }  

    @Override  
    public void deleteText(int begin, int end) {  
      // Replace all digits in the given range with zero:  
      StringBuilder builder = new StringBuilder(this.getText());  
      for (int c = begin; c<end; c++) {  
        if (c % 3 != 2) { // Not at a colon:  
          builder.replace(c, c+1, "0");  
        }  
      }  
      this.setText(builder.toString());  
    }  

    @Override  
    public void insertText(int index, String text) {  
      // Handle an insert by replacing the range from index to index+text.length() with text, if that results in a valid string:  
      StringBuilder builder = new StringBuilder(this.getText());  
      builder.replace(index, index+text.length(), text);  
      final String testText = builder.toString();  
      if (validate(testText)) {  
        this.setText(testText);  
      }  
      this.positionCaret(index + text.length());  
    }  


    @Override  
    public void replaceSelection(String replacement) {  
      final IndexRange selection = this.getSelection();  
      if (selection.getLength()==0) {  
        this.insertText(selection.getStart(), replacement);  
      } else {  
        this.replaceText(selection.getStart(), selection.getEnd(), replacement);  
      }  
    }  

    @Override  
    public void replaceText(IndexRange range, String text) {  
      this.replaceText(range.getStart(), range.getEnd(), text);  
    }  

    @Override  
    public void replaceText(int begin, int end, String text) {  
      if (begin==end) {  
        this.insertText(begin, text);  
      } else {  
      // only handle this if text.length() is equal to the number of characters being replaced, and if the replacement results in a valid string:  
      if (text.length() == end - begin) {  
        StringBuilder builder = new StringBuilder(this.getText());  
        builder.replace(begin, end, text);  
        String testText = builder.toString();  
        if (validate(testText)) {  
          this.setText(testText);  
        }  
          this.positionCaret(end);  
      }  
      }  
    }  

    private boolean validate(String time) {  
      if (! timePattern.matcher(time).matches()) {  
        return false ;  
      }  
      String[] tokens = time.split(":");  
      assert tokens.length == 3 ;  
      try {  
        int hours = Integer.parseInt(tokens[0]);  
        int mins = Integer.parseInt(tokens[1]);  
        int secs = Integer.parseInt(tokens[2]);  
        if (hours < 0 || hours > 23) {  
          return false ;  
        }  
        if (mins < 0 || mins > 59) {  
          return false ;  
        }  
        if (secs < 0 || secs > 59) {  
          return false ;  
        }  
        return true ;  
      } catch (NumberFormatException nfe) {  
        // regex matching should assure we never reach this catch block  
        assert false ;  
        return false ;  
      }  
    }  

    private final class TimeUnitBinding extends IntegerBinding {  

      final Unit unit ;  
      TimeUnitBinding(Unit unit) {  
        this.bind(textProperty());  
        this.unit = unit ;  
      }  
      @Override  
      protected int computeValue() {  
        // Crazy enum magic  
        String token = getText().split(":")[unit.ordinal()];  
        return Integer.parseInt(token);  
      }  

    }  

  }  
}  

Here is an example of a skin only that is for formatting money. link

    
23.08.2015 / 07:32
4

I think it would be ideal to use the JFXtras DatePicker :

    
04.08.2015 / 04:44