Windows C++中如何高亮搜索到的匹配字符串
Windows C++ GDI 搜索文本高亮实现方案
核心思路
你拿到的匹配起始下标是字符级的位置,只需要通过GDI提供的字符串尺寸计算接口,把「匹配位置之前的所有字符的像素总宽度」算出来,叠加到你原本的文本绘制起始X坐标上,就能得到高亮片段的绘制坐标,再分三段绘制文本即可:
- 匹配位置前的普通文本:用默认样式绘制
- 匹配到的目标文本:用高亮样式绘制
- 匹配位置后的普通文本:切回默认样式绘制
具体实现步骤
- 修正原搜索函数的冗余逻辑:你代码里的
searchForx没有定义,且const_cast属于不必要的危险操作,直接调用searchFor.c_str()即可传参给API。 - 调用
GetTextExtentPoint32计算字符串像素尺寸:这个API会基于当前DC选中的字体,返回给定字符串的像素宽高,是字符下标转像素坐标的核心接口。 - 拆分文本分段绘制:将原搜索字符串拆为前缀、匹配段、后缀三部分,按顺序调整绘制坐标和颜色即可完成高亮。
完整示例代码
#include <windows.h> #include <string> // 搜索函数,返回匹配起始位置,std::string::npos代表未匹配 std::size_t SearchText(const std::string& searchString, const std::string& searchFor) { return searchString.find(searchFor); } // 高亮绘制文本的函数 void DrawHighlightedText(HWND hWnd, int baseX, int baseY, const std::string& fullText, std::size_t matchPos, std::size_t matchLen) { HDC hDC = GetDC(hWnd); // 先把你要用的字体选入DC,这里用默认系统字体也可以,自行替换 HFONT hOldFont = (HFONT)SelectObject(hDC, GetStockObject(DEFAULT_GUI_FONT)); SetBkMode(hDC, OPAQUE); SIZE sz; int currentX = baseX; // 1. 绘制匹配前的前缀文本(默认样式) if (matchPos > 0 && matchPos != std::string::npos) { std::string prefix = fullText.substr(0, matchPos); // 计算前缀宽度 GetTextExtentPoint32A(hDC, prefix.c_str(), prefix.size(), &sz); // 默认颜色,可自行修改 SetBkColor(hDC, GetSysColor(COLOR_WINDOW)); SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); TextOutA(hDC, currentX, baseY, prefix.c_str(), prefix.size()); currentX += sz.cx; } // 2. 绘制匹配的高亮文本 if (matchPos != std::string::npos && matchLen > 0 && (matchPos + matchLen) <= fullText.size()) { std::string matchStr = fullText.substr(matchPos, matchLen); GetTextExtentPoint32A(hDC, matchStr.c_str(), matchStr.size(), &sz); // 高亮颜色:绿底紫字,和你给的示例一致 SetBkColor(hDC, RGB(0, 255, 0)); SetTextColor(hDC, RGB(255, 0, 255)); TextOutA(hDC, currentX, baseY, matchStr.c_str(), matchStr.size()); currentX += sz.cx; } // 3. 绘制匹配后的后缀文本(切回默认样式) std::string suffix; if (matchPos != std::string::npos) { suffix = fullText.substr(matchPos + matchLen); } else { suffix = fullText; } SetBkColor(hDC, GetSysColor(COLOR_WINDOW)); SetTextColor(hDC, GetSysColor(COLOR_WINDOWTEXT)); TextOutA(hDC, currentX, baseY, suffix.c_str(), suffix.size()); // 资源释放 SelectObject(hDC, hOldFont); ReleaseDC(hWnd, hDC); } // 调用示例 void TestHighlight(HWND hWnd) { std::string fullText = "这是一段测试文本,测试高亮功能"; std::string searchFor = "测试高亮"; std::size_t foundPos = SearchText(fullText, searchFor); if (foundPos != std::string::npos) { MessageBoxA(NULL, searchFor.c_str(), "字符串找到", MB_OK); } else { MessageBoxA(NULL, searchFor.c_str(), "未找到字符串", MB_OK); } // 绘制高亮文本,起始坐标(10,10)和你给的示例一致 DrawHighlightedText(hWnd, 10, 10, fullText, foundPos, searchFor.size()); }
注意事项
- 计算字符串尺寸必须和绘制使用同一个DC、同一种字体,否则宽度计算会出现偏差,导致高亮位置错位。
- 如果需要匹配多个结果,只需要循环调用
searchString.find(searchFor, lastPos + matchLen)遍历所有匹配位置,依次绘制多个高亮段即可。 - 如果是多行文本场景,你需要先自行对文本做换行排版,记录每行的起始字符索引和Y坐标,匹配到字符后先判断属于哪一行,再计算该行内的X偏移即可。
内容的提问来源于stack exchange,提问作者LoneWarrior ForgottenTrails
相关产品推荐
相关产品推荐

