JDK 1.8.0_131下JavaFX显示控制字符异常,如何修正?
I've noticed that on Windows 7, JavaFX (running on JDK 1.8.0_131) displays C1 control characters (Unicode U+0080 to U+009F) as various symbols. When I paste these characters into IntelliJ IDEA, I see similar results. I suspect this is font-related, but I can't reproduce the issue in non-Java applications using the Courier New font.
What's causing this behavior, and how can I modify it to display these control characters properly (or hide them)?
Reproducible Code
import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.TextField; import javafx.stage.Stage; public class ControlCharsJavaFx extends Application { public static void main(String[] args) { ControlCharsJavaFx.launch(ControlCharsJavaFx.class); } @Override public void start(Stage primaryStage) throws Exception { TextField textfield = new TextField(); textfield.setStyle("-fx-font-size: 500%"); for (int i = 128; i <= 159; i++) { textfield.setText(textfield.getText() + (char) i); } Scene test = new Scene(textfield); primaryStage.setScene(test); primaryStage.show(); } }
Answer
Why This Happens
Let’s break down the root causes here:
- Legacy JavaFX text rendering: The version of JavaFX bundled with JDK 1.8.0_131 has a text handling pipeline that doesn’t treat C1 control characters (U+0080-U+009F) as non-printable by default. Instead, it looks up glyphs for these code points in the active font. Many fonts (including fallback fonts JavaFX might use) include symbols here because these positions were repurposed for printable characters in legacy encodings like Windows-1252.
- Font fallback mismatch: Even if you specify Courier New, JavaFX might fall back to another font for characters it thinks aren’t present in Courier New. Native Windows apps handle this fallback differently, which is why you don’t see the issue outside Java.
- IntelliJ’s shared logic: Older versions of IntelliJ use a text rendering engine that may share similar font fallback behavior with Java, hence the identical visual result when pasting.
How to Fix It
Here are practical solutions tailored to your scenario:
1. Filter C1 Controls Before Display
If you don’t need these characters visible, strip or replace them before setting text in the TextField:
@Override public void start(Stage primaryStage) throws Exception { TextField textfield = new TextField(); textfield.setStyle("-fx-font-size: 500%"); for (int i = 128; i <= 159; i++) { char c = (char) i; // Replace with space, placeholder, or omit entirely textfield.setText(textfield.getText() + (isC1Control(c) ? ' ' : c)); } Scene test = new Scene(textfield); primaryStage.setScene(test); primaryStage.show(); } private boolean isC1Control(char c) { return c >= 0x80 && c <= 0x9F; }
2. Use a TextFormatter to Auto-Filter Input
For dynamic input (like pasting), use TextFormatter to intercept and clean text automatically:
textfield.setTextFormatter(new TextFormatter<>(change -> { // Remove all C1 control characters from the input String filtered = change.getControlNewText().replaceAll("[\u0080-\u009F]", ""); change.setText(filtered); // Adjust caret and selection to match the filtered text change.setRange(0, change.getControlText().length()); change.setCaretPosition(filtered.length()); change.setAnchor(filtered.length()); return change; }));
3. Force a Font That Ignores C1 Controls
Some programming-focused fonts (like Consolas) don’t include glyphs for C1 controls, so they’ll display as empty spaces or standard control markers. Explicitly set such a font:
textfield.setStyle("-fx-font-family: 'Consolas'; -fx-font-size: 500%");
Test different system fonts to find one that behaves as expected on your Windows 7 machine.
4. Upgrade JavaFX/JDK
Newer versions of JavaFX (especially those decoupled from JDK 11+) have improved Unicode compliance and text rendering. Upgrading to a modern JDK (e.g., JDK 17 with JavaFX 21) will likely resolve this issue out of the box, as control character handling has been refined.
内容的提问来源于stack exchange,提问作者Gille de Ray Ban

