如何通过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
相关产品推荐
相关产品推荐

