【问题标题】:How to correct Greek accented characters in a TextField如何更正 TextField 中的希腊重音字符
【发布时间】:2019-08-28 15:02:33
【问题描述】:

我面临的问题是当我有一个输入(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();
    }
}

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

已安装 JRE:jre1.8.0_221

安装的JDK:jdk1.8.0_221

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

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

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

编辑 2: 我也可以使用下面的代码破解它,但如果我决定这样做,我必须为我所有的 TextFields 这样做,这是我想要的避免。否则我应该创建一个“虚拟”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;
}));

【问题讨论】:

  • 你试过键盘上的al+0207吗?
  • 另外,你的 hack 很不错,但在这种情况下建议使用 TextFormatter。
  • @fuggerjaki61 在我的主项目中,我使用编码为 UTF-8 的 FXML 加载所有视图,并且我已经使用 UTF-16 对其进行了测试。我也尝试使用多个字体系列。这不太可能是字体问题,因为否则我将无法像在上面的示例中那样首先“硬编码”这个词。
  • FWIW 有人在 4 年前在 reddit.com/r/javahelp/comments/2y69co/… 遇到了同样的问题,但我在那里没有看到解决方案。这可能是TextField 的错误吗?
  • 还有!这是一个类似的问题(但针对JTextField),用户报告说操作系统之间的行为有所不同。 stackoverflow.com/questions/24017029/…

标签: java javafx


【解决方案1】:

我可以重现该行为。如果您将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

【讨论】:

  • 嗯,或多或少的结论是,在键释放事件之后,键的映射可能存在错误,您的解决方案也很有趣。让这个赏金丢失所以它是你的可能是一种浪费;)
【解决方案2】:

我认为这是希腊键盘的问题。我尝试使用另一个文本字段(Opera 搜索栏、Google 搜索栏等),但我无法编写此字符。你只能用 Alt+0239 组合写这个。您可以尝试使用“field2.setOnKeyPressed()”创建组合。

【讨论】:

    猜你喜欢
    • 2014-06-14
    • 2020-10-16
    • 2016-04-02
    • 2013-09-30
    • 2016-12-28
    • 1970-01-01
    • 2011-08-28
    • 1970-01-01
    • 2020-11-03
    相关资源
    最近更新 更多