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

Win32 C++:如何实现无边界无分隔且抓手着色的扁平状态栏

Win32 C++ 实现无间隙扁平彩色状态栏

需求

实现类似Visual Studio/VS Code风格的扁平彩色状态栏,要求:

  • 无分隔线、无区域边框
  • 包含「Selected」和「Total」两个自定义区域

已尝试的方案及问题

方案1:自绘区域(SBT_OWNERDRAW | SBT_NOBORDERS)

给每个区域设置自绘标记,在WM_DRAWITEM中自定义绘制背景和文本:

SendMessage(hWndStatusBar, SB_SETTEXT,   
            (WPARAM)itemIndex | SBT_OWNERDRAW | SBT_NOBORDERS,
            (LPARAM)L"");

// WndProc中处理WM_DRAWITEM
case WM_DRAWITEM:
{
    LPDRAWITEMSTRUCT pDis = (LPDRAWITEMSTRUCT)lParam;
    // 验证是状态栏控件
    RECT textRect = pDis->rcItem;
    SetBkMode(pDis->hDC, OPAQUE);
    SetBkColor(pDis->hDC, RGB(255,0,0));
    // 绘制区域背景
    HBRUSH hBrush = CreateSolidBrush(RGB(255,0,0));
    FillRect(pDis->hDC, &pDis->rcItem, hBrush);
    DeleteObject(hBrush);
    // 绘制文本
    DrawText(pDis->hDC, partText.c_str(), -1, &textRect, DT_SINGLELINE | DT_VCENTER | DT_LEFT);
}
break;

问题:自定义区域已着色,但状态栏仍存在未填充的边框间隙,FillRect无法覆盖间隙区域。

方案2:全局背景色+禁用主题

通过SB_SETBKCOLOR设置状态栏全局背景色,同时禁用系统主题:

SetWindowTheme(hWndStatusBar, L"", L"");
SendMessage(hWndStatusBar, SB_SETBKCOLOR, 0, (LPARAM)RGB(255, 0, 0));

问题:边框间隙消除,但自定义区域(抓手区域)未被着色,无法区分不同区域。

解决方案

结合两种方案的优势,同时处理全局背景和自定义区域绘制,消除间隙并实现区域着色:

步骤1:初始化状态栏基础样式

禁用系统主题,避免默认边框干扰,同时设置全局背景色填充间隙:

// 禁用状态栏的Windows主题
SetWindowTheme(hWndStatusBar, L"", L"");
// 设置状态栏全局背景色(填充间隙区域)
SendMessage(hWndStatusBar, SB_SETBKCOLOR, 0, (LPARAM)RGB(240, 240, 240));
// 设置状态栏分区(示例:Selected占150px,Total占剩余空间)
int parts[] = {150, -1};
SendMessage(hWndStatusBar, SB_SETPARTS, _countof(parts), (LPARAM)parts);

步骤2:设置区域为自绘模式

给「Selected」和「Total」区域标记为自绘+无边框:

// 假设itemIndex0是Selected区域,itemIndex1是Total区域
SendMessage(hWndStatusBar, SB_SETTEXT, (WPARAM)0 | SBT_OWNERDRAW | SBT_NOBORDERS, (LPARAM)L"");
SendMessage(hWndStatusBar, SB_SETTEXT, (WPARAM)1 | SBT_OWNERDRAW | SBT_NOBORDERS, (LPARAM)L"");

步骤3:自定义绘制区域(WM_DRAWITEM)

调整绘制矩形覆盖间隙,同时自定义区域背景和文本样式:

case WM_DRAWITEM:
{
    LPDRAWITEMSTRUCT pDis = (LPDRAWITEMSTRUCT)lParam;
    // 过滤非状态栏的绘制请求
    if (pDis->hwndItem != hWndStatusBar) break;

    // 扩大绘制矩形,覆盖默认间隙(偏移量可根据实际情况调整)
    RECT fullRect = pDis->rcItem;
    fullRect.left -= 2;
    fullRect.right += 2;
    fullRect.top -= 1;
    fullRect.bottom += 1;

    // 区分区域设置背景色
    COLORREF bgColor;
    COLORREF textColor;
    CString displayText;
    if (pDis->itemID == 0) {
        // Selected区域:蓝色背景+白色文本
        bgColor = RGB(0, 120, 215);
        textColor = RGB(255, 255, 255);
        displayText = L"Selected: 5";
    } else {
        // Total区域:浅灰背景+黑色文本
        bgColor = RGB(220, 220, 220);
        textColor = RGB(0, 0, 0);
        displayText = L"Total: 20";
    }

    // 绘制区域背景
    HBRUSH hBrush = CreateSolidBrush(bgColor);
    FillRect(pDis->hDC, &fullRect, hBrush);
    DeleteObject(hBrush);

    // 设置文本样式并绘制
    SetTextColor(pDis->hDC, textColor);
    SetBkMode(pDis->hDC, TRANSPARENT);
    RECT textRect = pDis->rcItem;
    textRect.left += 4; // 增加文本内边距
    DrawText(pDis->hDC, displayText, -1, &textRect, DT_SINGLELINE | DT_VCENTER | DT_LEFT);
}
break;

原理说明

  1. SetWindowTheme禁用系统主题后,状态栏不会渲染默认的边框和阴影;
  2. SB_SETBKCOLOR设置全局背景色,填充了方案1中出现的间隙区域;
  3. 自绘时扩大绘制矩形,确保自定义背景完全覆盖区域及周边间隙,实现真正的无边框效果;
  4. 区分区域设置不同的背景色,满足「Selected」和「Total」的视觉区分需求。

内容的提问来源于stack exchange,提问作者gene b.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 04:27:26