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

Win32自定义标题栏:返回HTREDUCE等后显示系统按钮问题

解决自定义标题栏点击区域时出现系统默认按钮的问题

问题根源

当你在WM_NCHITTEST中返回HTREDUCE、HTZOOM、HTCLOSE这类非客户区命中测试值时,Windows系统会默认认为窗口存在原生标题栏按钮——即便你已经通过WM_NCCALCSIZE移除了系统标题栏,系统仍会自动绘制对应的原生按钮样式,这就是你看到丑陋系统按钮的原因。

解决方案

要彻底避免系统绘制默认按钮,需要调整窗口样式并自行处理按钮的点击逻辑:

  1. 移除窗口的WS_SYSMENU样式
    这个样式会让系统保留绘制系统菜单及相关按钮的逻辑,必须移除。

  2. 修改WM_NCHITTEST处理逻辑
    仅返回HTCAPTION实现标题栏拖拽,不再返回按钮相关的非客户区测试值,将按钮点击交给鼠标消息处理。

  3. 自行处理按钮点击事件
    在WM_LBUTTONDOWN中判断点击位置是否在自定义按钮区域,调用对应API执行最小化、最大化、关闭操作。

修改后的代码示例

创建窗口(移除WS_SYSMENU)

HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW & ~WS_SYSMENU,
    CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

WM_NCHITTEST处理(仅保留拖拽逻辑)

case WM_NCHITTEST:
{
    auto x = GET_X_LPARAM(lParam);
    auto y = GET_Y_LPARAM(lParam);
    RECT rect;
    GetWindowRect(hWnd, &rect);
    if (y - rect.top < 40) {
        // 仅标记为标题栏区域,支持窗口拖拽
        return HTCAPTION;
    }
    return DefWindowProc(hWnd, WM_NCHITTEST, wParam, lParam);
}

添加WM_LBUTTONDOWN处理按钮点击

case WM_LBUTTONDOWN:
{
    POINT pt;
    GetCursorPos(&pt);
    RECT windowRect;
    GetWindowRect(hWnd, &windowRect);
    const int btnWidth = 120;
    const int titleBarHeight = 40;

    // 计算各按钮的屏幕坐标范围
    RECT minBtn = {
        windowRect.right - 3 * btnWidth,
        windowRect.top,
        windowRect.right - 2 * btnWidth,
        windowRect.top + titleBarHeight
    };
    RECT maxBtn = {
        windowRect.right - 2 * btnWidth,
        windowRect.top,
        windowRect.right - btnWidth,
        windowRect.top + titleBarHeight
    };
    RECT closeBtn = {
        windowRect.right - btnWidth,
        windowRect.top,
        windowRect.right,
        windowRect.top + titleBarHeight
    };

    if (PtInRect(&minBtn, pt)) {
        ShowWindow(hWnd, SW_MINIMIZE);
    } else if (PtInRect(&maxBtn, pt)) {
        ShowWindow(hWnd, IsZoomed(hWnd) ? SW_RESTORE : SW_MAXIMIZE);
    } else if (PtInRect(&closeBtn, pt)) {
        DestroyWindow(hWnd);
    }
    return 0;
}

额外优化

如果需要实现按钮的hover、按下等交互效果,还需处理WM_MOUSEMOVE和WM_LBUTTONUP消息,更新按钮状态并调用InvalidateRect触发重绘,让自定义按钮的交互体验更接近原生。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:15:52