java - 如何更正 TextField 中的希腊重音字符

标签 java javafx

我面临的问题是当我有一个输入(TextField、TextArea 等)并且我试图插入一些包含重音字符的希腊词时。像“Γάτα”(猫)这样的词效果很好。不幸的是,我无法类型 像“Ταϊτή”(塔希提岛)这样的词。如果我尝试复制和粘贴它或对其进行硬编码,它工作正常,但是当我尝试使用

Shift + ';' + ι

这应该产生'ϊ',而不是我得到'¨ι'

这是一个例子:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Example extends Application {

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

    @Override
    public void start(Stage stage) throws Exception {

        VBox mainBox = new VBox(10);
        mainBox.setPadding(new Insets(20));
        mainBox.setAlignment(Pos.CENTER);

        // Ταϊτή = Tahiti
        TextField field1 = new TextField("Ταϊτή");
        TextField field2 = new TextField();

        mainBox.getChildren().add(field1);
        mainBox.getChildren().add(field2);

        field1.setStyle("-fx-font-size:24px");
        field2.setStyle("-fx-font-size:24px");

        stage.setScene(new Scene(mainBox));
        stage.show();
    }
}

下图显示了我自己输入单词时的结果

enter image description here

已安装的 JRE:jre1.8.0_221

安装的JDK:jdk1.8.0_221

为了排除 IDE (Eclipse) 作为问题的原因,我在 SceneBuilder 上仅使用一个 AnchorPane 和一个 TextField 测试了这种行为,我在那里也遇到了同样的问题。但是为了论证,我在 Eclipse 中使用编辑器和所有设置来使用编码 UTF-8。

所以我想问一下:这是当前 JRE/JDK 的一个错误,如果是,是否有一个众所周知的解决方案我可以使用,或者我应该使用一个监听器来捕获输入并自己纠正它?

编辑:正如 Sedrick 指出的那样,我可以使用 alt + 0 2 3 9 的组合,但这将产生一种与希腊字母相似但不相同的不同类型的字母。看看下面的图片。不幸的是,这不是我的客户想要的行为,因为正确的输入方式(在希腊键盘中)是使用 : Shift + ';' + ι ,其中“ι”是英文字母“i”。

enter image description here

编辑 2:我也可以通过使用下面的代码来绕过它,但如果我决定这样做,我必须为我所有的 TextField 这样做,这是我想避免的。否则,我应该创建一个“虚拟”CustomTextField 类,它将扩展 TextField 并在那里实现 hack,然后我可以用 CustomTextField 替换我项目中的所有 TextField 引用。
field2.setTextFormatter(new TextFormatter<>(c -> {
    String text = c.getControlNewText();

    if (text.contains("¨ι") || text.contains("¨Ι")) { 

        // In order to "catch" a word with multiple wrong characters
        // for example if someone tries to copy/paste, I will use
        // the replaceAll() method
        text = text.replaceAll("¨ι", "ϊ");
        text = text.replaceAll("¨Ι", "Ϊ"); 

        // update the field 
        field2.setText(text);

        // correct the caret and anchor positions
        c.setCaretPosition(c.getCaretPosition() - 1);
        c.setAnchor(c.getCaretPosition());

        c.setText(""); // consume change because we already update it
    }
    return c;
}));

最佳答案

我可以重现这种行为。如果您添加 EventHandler到你的舞台你就可以清楚地看到问题所在。

stage.addEventFilter(KeyEvent.KEY_TYPED, ev -> {
    System.out.println("Key typed: " + ev.getCharacter());
});

输出:
Key typed: ¨
Key typed: Ι
Key typed: ¨
Key typed: ι

有一个resolved ticket描述这个问题。如果是 Glass Windowing Toolkit问题我们对此无能为力,只能提交错误报告。

不知道你能不能抓到这些之前输入的键KeyEvents已发送,但您可以在阶段级别过滤它们。
stage.addEventFilter(KeyEvent.KEY_TYPED, new KeyTypedListener());

这不是很好,而是一种更“全局”的改变行为的方式。
public class KeyTypedListener implements EventHandler<KeyEvent> {

    private boolean disabled = false;
    private Map<String, String> charCombinations = new HashMap<>();
    private KeyEvent pendingEvent;

    public KeyTypedListener() {
        charCombinations.put("¨ι", "ϊ");
        charCombinations.put("¨Ι", "Ϊ");
    }

    @Override
    public void handle(final KeyEvent event) {

        if (disabled || event.getCharacter() == null
                || event.getCharacter().length() != 1) {
            return;
        }

        final String typed = event.getCharacter();

        if (pendingEvent == null && isCombiCharacter(typed)) {
            pendingEvent = event.copyFor(event.getSource(), event.getTarget());
            event.consume();

        } else if (pendingEvent != null) {
            String combination =
                    charCombinations.get(pendingEvent.getCharacter() + typed);

            if (combination == null) {
                disabled = true;
                fireEvent(pendingEvent);
                disabled = false;
                pendingEvent = null;
            } else {
                event.consume();
                pendingEvent = null;

                Platform.runLater(() -> {
                    fireEventWithCharacter(event, combination);
                });
            }
        }
    }

    private boolean isCombiCharacter(final String character) {
        return "¨".equals(character);
    }

    private void fireEvent(final KeyEvent event) {
        Event.fireEvent(event.getTarget(), event);
    }

    private void fireEventWithCharacter(final KeyEvent event,
            final String character) {
        fireEvent(new KeyEvent(event.getSource(), event.getTarget(),
                event.getEventType(), character, "", KeyCode.UNDEFINED,
                event.isShiftDown(), event.isControlDown(), event.isAltDown(),
                event.isMetaDown()));
    }
}

当然你也可以新建一个EventDispatcher .

关于java - 如何更正 TextField 中的希腊重音字符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57695318/

相关文章:

java - android AysncTask doInbackground

java - 空 transient 属性

java - 携带相同时间戳的对象的值累加

java - 如何让多个文本框以随机方向移动,并且它们之间有特定的时间间隔?

JavaFX 当组件不可见时填充空白?

javascript - 使用 JavaScript 获取 jar 文件中配置的环境变量

未显示 Java 按钮?

java - 在 JavaFx 中创建自定义控件的问题

java - 在 JavaFX 中连接 View 和模型的主要方式是什么?

javafx - 一个 Controller 到 2 个 fxmls (JavaFX)