2

在文本字段中,我想通过以下方式执行操作:

-> 默认文本 00:00:00 设置为时间,因为文本字段用于时间并且字段的字符长度为 8。

-> 如果光标位于位置 0(零)并且如果我按下数字键,它应该替换位置 0 值并将光标移动到下一个位置。

   eg : 00:00:00
        20:00:00

解释:现在光标 z 在位置 0 并且我按下键 2 它应该替换位置 0 中的值 0 并移动到位置 1

当我按下任何非数字键时,它不应该替换任何值,但光标应该移动到下一个位置。

4

2 回答 2

2

这完美地工作:

    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);  
      }  

    }  

  }  
} 
于 2013-06-20T08:07:38.507 回答
1

我会为关键类型的事件注册一个事件监听器,例如

myTextField.setOnKeyTyped( new EventListener<KeyEvent>() { ...handler_code... });

此侦听器将告诉您刚刚键入的内容,您应该可以访问侦听器中的文本字段,以便确定插入符号的位置。这应该是您需要的所有信息。

例如,如果用户键入数字,则删除插入符号右侧的字符,如果用户按下非数字键,则删除插入符号左侧的字符。显然需要额外的检查来处理冒号和字符串的结尾。

于 2013-06-19T12:21:05.160 回答