我创建了一个扩展TextField的自定义组件,允许对特定类型的字符串进行高级编辑.
箭头键已经被重新定义,以允许特定的行为,应该不会触发默认插入符移动,但是我似乎不能够从移动停止.我已经消耗了()我能想象到的每种类型的事件,当按下箭头键时,插入符将始终移动.
此外,当键入新字母时,它首先被验证,如果发现无效,则撤消编辑.但是,当您输入的字母无效时,插入符始终移动一个位置,而不应移动.
我目前有逻辑,它将把插入符移动到正确的位置,因此控件或多或少有效,唯一的问题是当代码试图对抗默认移动时,用户看到插入符号疯狂地跳来跳去.
有趣的是:我为控件提供了一个上下文菜单,当显示上下文菜单时,插入符号会停止其默认移动(或者它突然足够快,因此用户看不到它).
我正在深入研究上下文菜单的源代码,看它是否设置或取消设置,但我没有看到它.有任何想法如何停止文本字段的默认插入符号移动?
您可以使用事件过滤器来阻止节点处理左箭头和右箭头:
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)