You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swing文本组件选中时连字与字距调整失效问题

连字(Ligatures)

在Java 17中使用Swing时,遇到了一些奇怪的渲染故障:启用字体连字并切换到连字密集的字体(如Fira Code),选中文本的部分连字内容会出现以下现象:

  • 选中的文本似乎脱离上下文重新渲染,但连字外的部分保持不变。
    [连字失效示例]:选中的连字文本与未选中部分样式脱节,连字效果异常
  • 取消选中后,文本光标(caret)会在字母间留下未渲染的空白。
    [取消选连字文本留下未渲染空白]:取消选中操作后,光标位置出现空白区域
  • 上述两个问题可能同时出现,导致内容难以辨认。
    [两个问题同时出现]:连字失效与空白区域同时存在,文本可读性严重下降
字距调整(Kerning)

使用字距调整密集的字体(如Windows 11新默认字体Segoe UI或Segoe UI Variable)时,会出现以下故障:

  • 选中的文本重新渲染时未结合全文本上下文计算字距。
    [字距调整文本选中重渲染动画]:选中文本的字距未按全文本上下文计算,样式发生突变
  • 在长段字距调整后的文本中放置光标几乎不可能——内部选择逻辑似乎基于未调整字距的版本计算目标位置。
    [字距调整文本选中偏移故障动画]:光标定位逻辑依赖未调整字距的文本,无法准确放置光标
  • 取消选中时,字距调整后的文本也无法正确重新渲染。
    [取消选字距文本留下未渲染空白动画]:取消选中后,文本无法恢复正确的字距渲染,出现空白区域
分析

该现象至少从Java 1.8版本开始出现,未测试更早版本。不同LAF(外观风格)对故障无影响。问题根源疑似为java.desktop/javax.swing.text.PlainView,尤其是其将文本拆分为可分段处理、仅重渲染“损坏”文本(updateDamage#668)及计算变更边界框的方式。

临时解决方案

唯一稳定有效的解决方案是禁用字距调整和连字。尝试自定义PlainView类接入Swing,但其架构不支持此类修复。

问题咨询

为更好理解问题,特提出以下疑问:

  • 是否遇到过此类问题?测试示例是否过于特殊?
  • 其他渲染管线是否也受影响?仅在Windows 11测试,推测可能受影响。
  • 问题源于JVM标准库还是存储的字体指标非标准?
  • 是否了解其他可改善情况的临时解决方案?
  • 能否替换Swing默认的字体渲染管线?

感谢帮助!以下为测试源码及机器配置:

补充:
该问题在Mac OSX Big Sur和Java 17环境下也存在,使用默认字体Helvetica时会出现连字和字距调整相关渲染异常,这表明问题可能源于JDK。

import javax.swing.*;
import java.awt.*;
import java.awt.font.*;
import java.util.*;


/**
        Tested on: Edition Windows 11 Pro
        Version    22H2
        OS build   22623.875
        Experience Windows Feature Experience Pack 1000.22636.1000.0
        
        openjdk 17.0.4.1 2022-08-12
        OpenJDK Runtime Environment Temurin-17.0.4.1+1 (build 17.0.4.1+1)
        OpenJDK 64-Bit Server VM Temurin-17.0.4.1+1 (build 17.0.4.1+1, mixed mode, sharing)
**/
public class Main {
    private static final boolean TEST_KERNING = true;
    private static final boolean TEST_LIGATURES = true;
    private static final String TEST_FONT = "Segoe UI Variable";
    private static final Number TEST_FONT_SIZE = 40;
    private static final Number TEST_FONT_WIDTH = TextAttribute.WEIGHT_BOLD;

    public static void main(String[] args) throws Exception {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

        Map<TextAttribute, Object> textAttributes = new HashMap<>();
        textAttributes.put(TextAttribute.FAMILY, TEST_FONT);
        textAttributes.put(TextAttribute.SIZE, TEST_FONT_SIZE);
        textAttributes.put(TextAttribute.WEIGHT, TEST_FONT_WIDTH);
        if(TEST_KERNING)
            textAttributes.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
        if(TEST_LIGATURES)
            textAttributes.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON);
        Font font = Font.getFont(textAttributes);

        JTextField txtInput = new JTextField();
        txtInput.setFont(font);

        JFrame frame = new JFrame("Demo");
        frame.setSize(400, 100);
        frame.add(txtInput);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

        SwingUtilities.invokeAndWait(() ->
            frame.setVisible(true)
        );
    }
}

内容的提问来源于stack exchange,提问作者calaedo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 00:10:32