JavaFX文本字段:禁用光标移动

nab*_*lex 2 javafx

我创建了一个扩展TextField的自定义组件,允许对特定类型的字符串进行高级编辑.

箭头键已经被重新定义,以允许特定的行为,应该不会触发默认插入符移动,但是我似乎不能够从移动停止.我已经消耗了()我能想象到的每种类型的事件,当按下箭头键时,插入符将始终移动.

此外,当键入新字母时,它首先被验证,如果发现无效,则撤消编辑.但是,当您输入的字母无效时,插入符始终移动一个位置,而不应移动.

我目前有逻辑,它将把插入符移动到正确的位置,因此控件或多或少有效,唯一的问题是当代码试图对抗默认移动时,用户看到插入符号疯狂地跳来跳去.

有趣的是:我为控件提供了一个上下文菜单,当显示上下文菜单时,插入符号会停止其默认移动(或者它突然足够快,因此用户看不到它).

我正在深入研究上下文菜单的源代码,看它是否设置或取消设置,但我没有看到它.有任何想法如何停止文本字段的默认插入符号移动?

jew*_*sea 5

您可以使用事件过滤器来阻止节点处理左箭头和右箭头:

textField.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
  @Override public void handle(KeyEvent keyEvent) {
    switch (keyEvent.getCode()) {
      case LEFT:
      case RIGHT:
        keyEvent.consume();
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

这有点奇怪,因为TextField将不再像用户通常期望的那样行事.

可执行样本

import javafx.application.*;
import javafx.beans.*;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TextFieldControl extends Application {
  @Override public void start(Stage stage) {
    final TextField textField = new TextField("Phone: ");
    textField.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
      @Override
      public void handle(KeyEvent keyEvent) {
        switch (keyEvent.getCode()) {
          // block cursor control keys.
          case LEFT:
          case RIGHT:
          case UP:
          case DOWN:
          case PAGE_UP:
          case PAGE_DOWN:
          case HOME:
          case END:
            keyEvent.consume();

          // allow deletion and tab.
          case DELETE:
          case BACK_SPACE:
          case TAB:
            return;
        }

        // only allow digits and a few punctuation symbols to be entered.
        if (!"0123456789-() ".contains(keyEvent.getCharacter())) {
          keyEvent.consume();
        }
      }
    });

    textField.focusedProperty().addListener(new InvalidationListener() {
      @Override public void invalidated(Observable observable) {
        // due to some weirdness JavaFX will auto select the text when the text field
        // receives focus, so instead deselect and position the caret at the end of the field.
        // Another weird thing is that a pulse must be run before the deselection or caret
        // positioning request occurs or it won't take effect, so a runnable seems to suffic to ensure that.
        Platform.runLater(new Runnable() {
          @Override public void run() {
            textField.deselect();
            textField.positionCaret(textField.getText().length());
          }
        });
      }
    });

    VBox layout = new VBox();
    layout.getChildren().setAll(new VBox(textField, new TextField()));
    stage.setScene(new Scene(layout));
    stage.show();

    textField.requestFocus();
  }

  public static void main(String[] args) {
    launch(args);
  }
}
Run Code Online (Sandbox Code Playgroud)