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

如何通过WinAPI将Toolbar置于非客户区,避免覆盖客户区控件?

问题

我未使用资源文件创建了一个Toolbar,但它处于客户区,导致在坐标(0,0)创建的Button控件被覆盖。我希望将Toolbar放在非客户区,使客户区控件可使用(0,0)坐标正常创建,就像使用MFC时的效果。

解决方案

要实现Toolbar位于非客户区且客户区自动适配,需完成以下关键修改:

  • 给Toolbar添加CCS_TOP | CCS_NODIVIDER | CCS_NOPARENTALIGN样式,使其固定在窗口顶部的非客户区域
  • 处理WM_NCCALCSIZE消息,调整客户区的顶部边界,避开Toolbar的高度
  • 处理WM_SIZE消息,窗口大小变化时同步调整Toolbar宽度,使其与窗口匹配
  • 全局保存Toolbar句柄,方便在消息处理中访问
修改后的完整代码
#include <windows.h>
#include <strsafe.h>
#include <commctrl.h>
#include <shlobj.h>
#include <shellapi.h>

// TOOL
#define IDB_TOOLBAR_START 301
#define IDB_TOOLBAR_STOP 302
#define IDB_TOOLBAR_TDSET 303
#define IDB_TOOLBAR_XTSET 304
#define IDB_TOOLBAR_HELP 306
// MENU
#define IDM_MENU_OPEN 320
#define IDM_MENU_CLOSE 321
#define IDM_MENU_EXIT 322
#define IDM_MENU_FIND 323
#define IDM_MENU_RUN 324
#define IDM_MENU_STOP 325
#define IDM_MENU_OPTIONS 326
#define IDM_MENU_ABOUT 327

HWND m_hToolBar = NULL; // 全局保存Toolbar句柄

LRESULT CreateToolBar(HWND hWnd)
{
    LPITEMIDLIST pidl = {0};
    SHGetSpecialFolderLocation(hWnd, CSIDL_DESKTOP, &pidl);
    SHFILEINFO sfi = {0};
    // 从系统里随机抽取icon图标
    HIMAGELIST hImageList = (HIMAGELIST)::SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);

    // 创建工具条控件,添加非客户区相关样式
    m_hToolBar = CreateWindow(TOOLBARCLASSNAME, NULL,
                               WS_CHILD | WS_VISIBLE | CCS_TOP | CCS_NODIVIDER | CCS_NOPARENTALIGN,
                               0, 0, 0, 0, hWnd, (HMENU)1,
                               NULL, NULL);

    // 设置工具条的图片列表
    ::SendMessage(m_hToolBar, TB_SETIMAGELIST, 0, (LPARAM)hImageList);

    // 添加一些按钮到工具条
    const UINT uButtonNums = 5;
    UINT uImgCount = ImageList_GetImageCount(hImageList);
    TBBUTTON tbButtons[uButtonNums] = {
        {MAKELONG(rand() % uImgCount, 0), IDB_TOOLBAR_START, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)TEXT("start")},
        {MAKELONG(rand() % uImgCount, 0), IDB_TOOLBAR_STOP, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)TEXT("stop")},
        {MAKELONG(rand() % uImgCount, 0), IDB_TOOLBAR_TDSET, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)TEXT("channel settings")},
        {MAKELONG(rand() % uImgCount, 0), IDB_TOOLBAR_XTSET, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)TEXT("system settings")},
        {MAKELONG(rand() % uImgCount, 0), IDB_TOOLBAR_HELP, TBSTATE_ENABLED, TBSTYLE_BUTTON | BTNS_AUTOSIZE, {0}, 0, (INT_PTR)TEXT("help")}};

    ::SendMessage(m_hToolBar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
    ::SendMessage(m_hToolBar, TB_ADDBUTTONS, (WPARAM)uButtonNums, (LPARAM)&tbButtons);

    // 自动调整工具条的大小并显示
    ::SendMessage(m_hToolBar, TB_AUTOSIZE, 0, 0);
    ::SendMessage(m_hToolBar, TB_SETSTYLE, 0, TBSTYLE_FLAT);
    ::ShowWindow(m_hToolBar, TRUE);
    return 0;
}

void AddMenus(HWND hWnd)
{
    HMENU m_hMenu = CreateMenu();
    HMENU hFileMenu = CreateMenu();
    HMENU hSubMenu = CreateMenu();
    HMENU hFind = CreateMenu();
    HMENU hRun = CreateMenu();
    HMENU hTools = CreateMenu();
    HMENU hHelp = CreateMenu();

    AppendMenu(m_hMenu, MF_POPUP, (UINT_PTR)hFileMenu, TEXT("File"));
    AppendMenu(m_hMenu, MF_POPUP, (UINT_PTR)hFind, TEXT("Find"));
    AppendMenu(m_hMenu, MF_POPUP, (UINT_PTR)hRun, TEXT("Run"));
    AppendMenu(m_hMenu, MF_POPUP, (UINT_PTR)hTools, TEXT("Tools"));
    AppendMenu(m_hMenu, MF_POPUP, (UINT_PTR)hHelp, TEXT("Help"));

    AppendMenu(hFileMenu, MF_STRING, 0, TEXT("New"));
    AppendMenu(hFileMenu, MF_POPUP, (UINT_PTR)hSubMenu, TEXT("Open SubMenu"));
    AppendMenu(hFileMenu, MF_SEPARATOR, 0, NULL);
    AppendMenu(hFileMenu, MF_STRING, IDM_MENU_CLOSE, TEXT("Close"));
    AppendMenu(hFileMenu, MF_STRING, IDM_MENU_EXIT, TEXT("Exit"));
    AppendMenu(hFind, MF_STRING, IDM_MENU_FIND, TEXT("Find"));
    AppendMenu(hRun, MF_STRING, IDM_MENU_RUN, TEXT("Run"));
    AppendMenu(hRun, MF_STRING, IDM_MENU_STOP, TEXT("Stop"));
    AppendMenu(hTools, MF_STRING, IDM_MENU_OPTIONS, TEXT("Options"));
    AppendMenu(hHelp, MF_STRING, IDM_MENU_ABOUT, TEXT("About"));

    AppendMenu(hSubMenu, MF_STRING, IDM_MENU_OPEN, TEXT("SubMenu Item"));

    SetMenu(hWnd, m_hMenu);
}

LRESULT CALLBACK WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        CreateWindow(WC_BUTTON, TEXT("Button"), WS_VISIBLE | WS_CHILD, 0, 0, 300, 100, hWnd, NULL, NULL, NULL);
        AddMenus(hWnd);
        CreateToolBar(hWnd);
        break;
    case WM_NCCALCSIZE:
        // 调整客户区大小,避开Toolbar
        if (m_hToolBar && wParam == TRUE)
        {
            NCCALCSIZE_PARAMS* pParams = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam);
            RECT& rcClient = pParams->rgrc[0];
            RECT tbRect;
            GetWindowRect(m_hToolBar, &tbRect);
            int tbHeight = tbRect.bottom - tbRect.top;
            rcClient.top += tbHeight;
            return 0;
        }
        break;
    case WM_SIZE:
        // 窗口大小变化时同步调整Toolbar宽度
        if (m_hToolBar)
        {
            RECT clientRect;
            GetClientRect(hWnd, &clientRect);
            SetWindowPos(m_hToolBar, NULL, 0, 0, clientRect.right, 0, SWP_NOZORDER | SWP_NOMOVE);
            SendMessage(m_hToolBar, TB_AUTOSIZE, 0, 0);
        }
        break;
    case WM_MOUSEMOVE:
    {
        int xPos = LOWORD(lParam);
        int yPos = HIWORD(lParam);
        TCHAR buffer[256];
        StringCchPrintf(buffer, 256, TEXT("xPos: %d, yPos: %d"), xPos, yPos);
        SetWindowText(hWnd, buffer);
        break;
    }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, BOOL)
{
    // 初始化通用控件
    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    icex.dwICC = ICC_BAR_CLASSES;
    InitCommonControlsEx(&icex);

    WNDCLASS wc = {0};
    wc.lpszClassName = TEXT("wndclass");
    wc.hbrBackground = CreateSolidBrush(RGB(255, 99, 71));
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpfnWndProc = WinProc;
    RegisterClass(&wc);

    HWND hWnd = CreateWindow(wc.lpszClassName, TEXT("Window"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, 0, 0, hInstance, 0);
    if (hWnd == NULL)
        return 1;
    ShowWindow(hWnd, SW_SHOWNORMAL);

    MSG msg = {0};
    while (GetMessage(&msg, 0, 0, 0))
    {
        DispatchMessage(&msg);
    }

    return 0;
}
编译命令
g++ dem01.cpp -o dem01 -g -static -Wall -std=c++11 -mwindows -lcomctl32 -lwinmm -lws2_32

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 05:24:54