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

如何在Eclipse SWT中获取字符实际占用的精确高度?

问题描述

我开发了一个Eclipse应用,需要获取文本实际占用区域的精确高度。但GC.textExtent方法无法满足需求:对于Arial这类非等宽字体,它返回的高度值对不同尺寸的字符(如'a'和带下沉的'j')是相同的,返回的矩形无法完全包含'j'、'g'这类带有下沉部分的字符。

我编写了测试代码复现该问题,在静态代码块中计算'a'和'j'的textExtent高度,结果二者均为21,触发了预期外的异常。代码如下:

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Display;

class SomeClass {

  ...

  static {
        Image imgTemp = new Image(Display.getDefault(), 123, 123);
        GC gcTemp = new GC(imgTemp);
        Font fontTemp = new Font(Display.getDefault(), "Arial", 13, SWT.NORMAL);

        int shortStringSize = gcTemp.textExtent("a").y;
        int tallStringSize = gcTemp.textExtent("j").y;

        imgTemp.dispose();
        fontTemp.dispose();
        gcTemp.dispose();
        
        if (shortStringSize == tallStringSize) {
            throw new RuntimeException("I expected letter 'a' have smaller"
                    + " text extent than letter 'j', because it is visually"
                    + " shorter.\n"
                    + "'j' size = " 
                    + tallStringSize 
                    + "\n"
                    + "'a' size = "
                    + shortStringSize);
        }
  }

...

}

错误输出如下:

<big stacktrace>

Caused by: java.lang.RuntimeException: I expected letter 'a' have smaller text extent than letter 'j', because it is visually shorter.
'j' size = 21
'a' size = 21
    at <my file>

<big stacktrace>

请问是否有办法获取依赖字符实际高度的字符串尺寸?


解决方案

核心原因

GC.textExtent()返回的高度是字体的标准行高(上升高度ascent + 下沉高度descent),这是字体设计时定义的统一高度,确保所有字符都能容纳在该范围内,因此无论单个字符的视觉形态如何,返回的高度值都相同。

两种可行方法

1. 使用GC.textBounds()获取字符精确边界

textBounds()会返回包围目标字符/字符串的最小矩形,矩形的高度即为该字符实际占用的垂直空间。注意必须先给GC设置目标字体,否则会使用默认字体导致结果错误。示例代码:

Image imgTemp = new Image(Display.getDefault(), 123, 123);
GC gcTemp = new GC(imgTemp);
Font fontTemp = new Font(Display.getDefault(), "Arial", 13, SWT.NORMAL);
gcTemp.setFont(fontTemp); // 必须设置GC的目标字体

// 获取'a'的实际边界矩形
Rectangle aBounds = gcTemp.textBounds(0, 0, "a");
int aActualHeight = aBounds.height;

// 获取'j'的实际边界矩形
Rectangle jBounds = gcTemp.textBounds(0, 0, "j");
int jActualHeight = jBounds.height;

// 清理资源
imgTemp.dispose();
fontTemp.dispose();
gcTemp.dispose();

2. 结合FontMetrics计算字符垂直范围

FontMetrics提供了字体的基线、最大上升/下沉高度等信息,配合textBounds可以更细致地获取字符的垂直位置信息:

Image imgTemp = new Image(Display.getDefault(), 123, 123);
GC gcTemp = new GC(imgTemp);
Font fontTemp = new Font(Display.getDefault(), "Arial", 13, SWT.NORMAL);
gcTemp.setFont(fontTemp);

FontMetrics metrics = gcTemp.getFontMetrics();
int baselineAscent = metrics.getAscent(); // 基线到字体顶部的距离

// 获取'j'的边界
Rectangle jBounds = gcTemp.textBounds(0, 0, "j");
// 字符顶部相对于基线的位置:baselineAscent + jBounds.y(jBounds.y通常为负值,代表向上偏移)
// 字符底部相对于基线的位置:jBounds.y + jBounds.height
// 字符实际高度即为jBounds.height

// 清理资源
imgTemp.dispose();
fontTemp.dispose();
gcTemp.dispose();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 14:23:15