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

SDL2中如何为TTF_RenderText生成的Surface添加字符下划线?

解决SDL2菜单快捷键下划线问题

方案一:修正Surface绘制下划线的方法

你之前的方法无效,核心问题是颜色值错误和坐标计算不准确,按下面步骤修改:

  1. 先将RGB颜色转换为Surface对应的像素格式值,不能直接用数字79
  2. 精确计算下划线的位置,不要假设所有字符宽度一致,单独计算目标字符前的文本宽度

示例代码:

// 定义颜色
SDL_Color RED = {255, 0, 0, 255};
SDL_Color UNDERLINE_COLOR = {0, 0, 0, 255}; // 自定义下划线颜色

// 渲染主文本
SDL_Surface* s_item = TTF_RenderText_Blended(font, ">  New game", RED);
if (!s_item) {
    // 处理渲染错误
}

// 计算目标字符"N"的起始位置:先算前缀">  "的宽度
int prefix_w, prefix_h;
TTF_SizeText(font, ">  ", &prefix_w, &prefix_h);
// 计算"N"的宽度
int char_w, char_h;
TTF_SizeText(font, "N", &char_w, &char_h);

// 定义下划线矩形:位于字符底部,高度3像素
SDL_Rect underline_rect = {
    prefix_w, // x坐标:前缀宽度即为"N"的起始位置
    s_item->h - 5, // y坐标:从Surface底部往上5像素(可调整)
    char_w,
    3
};

// 转换颜色为当前Surface的像素格式
Uint32 underline_pixel = SDL_MapRGB(s_item->format, UNDERLINE_COLOR.r, UNDERLINE_COLOR.g, UNDERLINE_COLOR.b);
// 填充矩形绘制下划线
SDL_FillRect(s_item, &underline_rect, underline_pixel);

// 转为纹理并释放Surface
items[n]->t = SDL_CreateTextureFromSurface(renderer, s_item);
SDL_FreeSurface(s_item);

方案二:拆分文本单独渲染下划线部分

如果需要更灵活的样式(仅给指定字符加下划线),可以把文本拆成普通部分和下划线部分,分别渲染后拼接:

// 渲染前缀文本
SDL_Surface* s_prefix = TTF_RenderText_Blended(font, ">  ", RED);
// 给目标字符设置下划线样式
TTF_SetFontStyle(font, TTF_STYLE_UNDERLINE);
SDL_Surface* s_underline_char = TTF_RenderText_Blended(font, "N", RED);
// 恢复字体默认样式
TTF_SetFontStyle(font, TTF_STYLE_NORMAL);
// 渲染后缀文本
SDL_Surface* s_suffix = TTF_RenderText_Blended(font, "ew game", RED);

// 创建拼接后的Surface
int total_w = s_prefix->w + s_underline_char->w + s_suffix->w;
SDL_Surface* s_item = SDL_CreateRGBSurface(0, total_w, s_prefix->h, 32, 0, 0, 0, 0);

// 复制各部分到新Surface
SDL_Rect dest_rect = {0, 0, 0, 0};
SDL_BlitSurface(s_prefix, NULL, s_item, &dest_rect);
dest_rect.x += s_prefix->w;
SDL_BlitSurface(s_underline_char, NULL, s_item, &dest_rect);
dest_rect.x += s_underline_char->w;
SDL_BlitSurface(s_suffix, NULL, s_item, &dest_rect);

// 转为纹理并释放临时Surface
items[n]->t = SDL_CreateTextureFromSurface(renderer, s_item);
SDL_FreeSurface(s_prefix);
SDL_FreeSurface(s_underline_char);
SDL_FreeSurface(s_suffix);
SDL_FreeSurface(s_item);

方案三:使用渲染目标绘制下划线(硬件加速)

如果你的纹理是硬件加速类型,可设置渲染目标后直接在纹理上绘制:

// 先计算文本总尺寸
int text_w, text_h;
TTF_SizeText(font, ">  New game", &text_w, &text_h);

// 创建可作为渲染目标的纹理
items[n]->t = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, 
    SDL_TEXTUREACCESS_TARGET, text_w, text_h);
// 设置当前渲染目标为该纹理
SDL_SetRenderTarget(renderer, items[n]->t);
// 清除纹理背景(可选)
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);

// 渲染文本到纹理
SDL_Surface* s_item = TTF_RenderText_Blended(font, ">  New game", RED);
SDL_Texture* text_tex = SDL_CreateTextureFromSurface(renderer, s_item);
SDL_RenderCopy(renderer, text_tex, NULL, NULL);
SDL_FreeSurface(s_item);
SDL_DestroyTexture(text_tex);

// 计算下划线位置(同方案一逻辑)
int prefix_w, prefix_h;
TTF_SizeText(font, ">  ", &prefix_w, &prefix_h);
int char_w, char_h;
TTF_SizeText(font, "N", &char_w, &char_h);

// 设置下划线颜色并绘制
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_Rect underline_rect = {prefix_w, text_h - 5, char_w, 3};
SDL_RenderFillRect(renderer, &underline_rect);

// 恢复默认渲染目标
SDL_SetRenderTarget(renderer, NULL);

原代码问题分析

  1. 颜色值错误:SDL_FillRect需要的是Surface像素格式对应的颜色值,直接传79是无效的,必须用SDL_MapRGB转换
  2. 坐标计算偏差:用char_w*3假设所有字符宽度一致,但实际空格和字母的宽度可能不同,导致下划线位置偏移
  3. 未检查错误:没有判断TTF_RenderText_Blended是否成功,若Surface创建失败,后续操作自然无效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 01:45:57