Java21.0.3绘制日期时间时出现非法矩形问题求助
问题描述

上图中时间值与“am”之间显示了一个矩形。在Java 21.0.3中,DateTime格式化后的字符串包含**NNBSP(窄不换行空格)**字符,该字符因当前使用的字体不支持,绘制时被渲染为矩形。
复现代码
public class RunningStringPanel extends JPanel implements ActionListener { private String text; public RunningStringPanel(String text, int delay) { this.text = text; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); g.setFont(new Font("MS Gothic", Font.ITALIC, 24)); System.out.println(text); g.drawString(text, 10, 50); // Draw the string up to the current index System.out.println(); } @Override public void actionPerformed(ActionEvent e) { repaint(); } public static void main(String[] args) { JFrame frame = new JFrame("Running String"); RunningStringPanel panel = new RunningStringPanel(getText(), 200); frame.add(panel); frame.setSize(400, 200); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } public static final Long LONG_TIME = 1573430400000L; public static String getText() { Date created = new Date(LONG_TIME); DateFormat format = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL); String value = format.format(created); return value; } }
已尝试的解决方法
- 设置
stdout.encoding和stderr.encoding为UTF-8 - 使用最新的DateFormatter API,问题依旧
- 将Windows区域设置改为UTF-8
疑问
有没有办法避免字符串中显示这个矩形?
解决方法
出现矩形的核心原因是MS Gothic字体不支持NNBSP(U+202F)字符,可通过以下方式解决:
- 替换NNBSP字符
在格式化后直接将NNBSP替换为字体支持的空格类型,比如普通空格:
public static String getText() { Date created = new Date(LONG_TIME); DateFormat format = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL); String value = format.format(created); // 替换窄不换行空格为普通空格 return value.replace('\u202F', ' '); }
- 更换支持NNBSP的字体
把绘制时使用的字体换成支持该字符的字体,比如Segoe UI、微软雅黑等:
@Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 改用Segoe UI字体 g.setFont(new Font("Segoe UI", Font.ITALIC, 24)); System.out.println(text); g.drawString(text, 10, 50); System.out.println(); }
- 自定义日期格式模板
绕过系统默认的FULL格式,手动指定日期输出模板,从根源避免NNBSP生成:
// 使用旧API的SimpleDateFormat public static String getText() { Date created = new Date(LONG_TIME); // 自定义格式,用普通空格分隔 SimpleDateFormat sdf = new SimpleDateFormat("EEEE, MMMM dd, yyyy hh:mm:ss a", Locale.US); return sdf.format(created); } // 或者使用Java 8+的新API public static String getText() { LocalDateTime dateTime = Instant.ofEpochMilli(LONG_TIME) .atZone(ZoneId.systemDefault()) .toLocalDateTime(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "EEEE, MMMM dd, yyyy hh:mm:ss a", Locale.US ); return dateTime.format(formatter); }
内容的提问来源于Stack Exchange,提问作者Margub Khan
相关产品推荐
相关产品推荐

