Win32 API:如何使用TextOut在工具栏空白区域绘制文本不被覆盖
工具栏子控件上方文本被遮挡的解决办法
问题原因
你当前的代码是在主窗口的WM_PAINT消息中绘制文本,而Windows系统的窗口绘制顺序是先绘制父窗口,再逐层绘制所有子窗口:主窗口绘制完成后,才会绘制工具栏、富文本框等一级子窗口,最后才会绘制工具栏内嵌的列表框、按钮等二级子窗口。你在主窗口绘制的文本处于最底层,会被后续绘制的子窗口内容完全覆盖,所以无法显示。
推荐解决方法
方案1:使用静态文本控件(最适合新手,无需处理绘制逻辑)
直接在工具栏上创建系统自带的静态文本控件展示标签,系统会自动处理层级和绘制,不会被其他控件覆盖。
在WM_CREATE创建完工具栏后,新增如下代码即可:
// 架构选择标签静态控件,坐标为相对于工具栏的客户区坐标 HWND hArchLabel = CreateWindow(WC_STATIC, ArchLabel, WS_CHILD | WS_VISIBLE | SS_LEFT, archListBoxPos + 20, 5, 100, 20, // 宽高可根据实际文本长度调整 Toolbar, (HMENU)(ChildID1 + 5), GetModuleHandle(NULL), NULL); // 编译按钮标签静态控件 HWND hBuildLabel = CreateWindow(WC_STATIC, BuildLabel, WS_CHILD | WS_VISIBLE | SS_LEFT, btListBoxPos, 5, 100, 20, Toolbar, (HMENU)(ChildID1 + 6), GetModuleHandle(NULL), NULL); // 可选:将静态控件设为顶层,避免被后续创建的控件遮挡 SetWindowPos(hArchLabel, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); SetWindowPos(hBuildLabel, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
创建完成后可以删除主窗口WM_PAINT中TextOut相关的绘制代码。
方案2:子类化工具栏自绘文本(适合需要自定义绘制效果的场景)
如果你需要自己用TextOut实现绘制,可以子类化工具栏窗口,在工具栏自身绘制完成后再绘制文本,保证文本层级高于工具栏背景,不会被工具栏自身的绘制覆盖。
实现步骤如下:
- 定义工具栏的子类化窗口过程和原窗口过程指针:
WNDPROC g_oldToolbarProc; LRESULT CALLBACK ToolbarSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_PAINT: // 先调用工具栏原有的窗口过程,完成工具栏背景、边框等基础绘制 LRESULT ret = CallWindowProc(g_oldToolbarProc, hWnd, msg, wParam, lParam); // 自定义绘制文本 HDC hdc = GetDC(hWnd); SetBkMode(hdc, TRANSPARENT); // 设置文本背景透明,和工具栏背景融合 SetTextAlign(hdc, TA_TOP); // 注意:此处坐标为相对于工具栏左上角的客户区坐标,不要使用主窗口坐标 TextOut(hdc, archListBoxPosInToolbar + 20, 5, ArchLabel, ARRAYSIZE(ArchLabel)); TextOut(hdc, btListBoxPosInToolbar, 5, BuildLabel, ARRAYSIZE(BuildLabel)); ReleaseDC(hWnd, hdc); return ret; default: return CallWindowProc(g_oldToolbarProc, hWnd, msg, wParam, lParam); } }
- 在
WM_CREATE中创建完工具栏后,绑定子类化过程:
g_oldToolbarProc = (WNDPROC)SetWindowLongPtr(Toolbar, GWLP_WNDPROC, (LONG_PTR)ToolbarSubclassProc);
如果不确定子控件在工具栏中的坐标,可以调用MapWindowPoints将主窗口坐标转换为工具栏相对坐标。
内容的提问来源于stack exchange,提问作者Dave B.
相关产品推荐
相关产品推荐

