SDL2中如何为TTF_RenderText生成的Surface添加字符下划线?
解决SDL2菜单快捷键下划线问题
方案一:修正Surface绘制下划线的方法
你之前的方法无效,核心问题是颜色值错误和坐标计算不准确,按下面步骤修改:
- 先将RGB颜色转换为Surface对应的像素格式值,不能直接用数字79
- 精确计算下划线的位置,不要假设所有字符宽度一致,单独计算目标字符前的文本宽度
示例代码:
// 定义颜色 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);
原代码问题分析
- 颜色值错误:
SDL_FillRect需要的是Surface像素格式对应的颜色值,直接传79是无效的,必须用SDL_MapRGB转换 - 坐标计算偏差:用
char_w*3假设所有字符宽度一致,但实际空格和字母的宽度可能不同,导致下划线位置偏移 - 未检查错误:没有判断
TTF_RenderText_Blended是否成功,若Surface创建失败,后续操作自然无效
内容的提问来源于stack exchange,提问作者realhllcngn
相关产品推荐
相关产品推荐

