Win32 UI工具栏位置过低问题排查求助
Win32工具栏位置异常(上方空白)问题排查与解决
问题描述
我正在学习Win32 UI开发,参考微软官方文档实现了一个工具栏示例,但运行后发现工具栏位置过低,上方出现大量空白。
以下是原代码:
#include <Windows.h> #include <CommCtrl.h> #include <cstdio> HIMAGELIST g_hImageList = NULL; const int IDM_NEW = 201; const int IDM_OPEN = 202; const int IDM_SAVE = 203; HWND MainWindowToolbar( HWND Window ) { // Declare and initialize local constants. const int ImageListID = 0; const int numButtons = 3; const int bitmapSize = 16; RECT MainWindowRect; GetClientRect(Window, &MainWindowRect); const DWORD buttonStyles = BTNS_AUTOSIZE; // Create the toolbar. HWND hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | TBSTYLE_WRAPABLE, 0, 0, 0, 0, Window, NULL, GetModuleHandle(NULL), NULL); if (hWndToolbar == NULL) return NULL; // Create the image list. g_hImageList = ImageList_Create(bitmapSize, bitmapSize, // Dimensions of individual bitmaps. ILC_COLOR16 | ILC_MASK, // Ensures transparent background. numButtons, 0); // Set the image list. SendMessage(hWndToolbar, TB_SETIMAGELIST, (WPARAM)ImageListID, (LPARAM)g_hImageList); // Load the button images. SendMessage(hWndToolbar, TB_LOADIMAGES, (WPARAM)IDB_STD_SMALL_COLOR, (LPARAM)HINST_COMMCTRL); // Initialize button info. // IDM_NEW, IDM_OPEN, and IDM_SAVE are application-defined command constants. TBBUTTON tbButtons[numButtons] = { { MAKELONG(STD_FILENEW, ImageListID), IDM_NEW, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"New" }, { MAKELONG(STD_FILEOPEN, ImageListID), IDM_OPEN, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"Open"}, { MAKELONG(STD_FILESAVE, ImageListID), IDM_SAVE, 0, buttonStyles, {0}, 0, (INT_PTR)L"Save"} }; // Add buttons. SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); SendMessage(hWndToolbar, TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)&tbButtons); // Resize the toolbar, and then show it. SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0); ShowWindow(hWndToolbar, TRUE); return hWndToolbar; } HWND TreeViewHandle; LRESULT CALLBACK MainWindowCallback( HWND Window, UINT Message, WPARAM WParam, LPARAM LParam ) { LRESULT Result; switch(Message) { case WM_CREATE: { MainWindowToolbar( Window ); } break; case WM_SIZE: { OutputDebugString("WM_SIZE\n"); } break; case WM_DESTROY: { PostQuitMessage(0); } break; case WM_CLOSE: { OutputDebugString("WM_CLOSE\n"); } break; case WM_ACTIVATEAPP: { OutputDebugString("WM_ACTIVATEAPP\n"); } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(Window, &ps); FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1)); EndPaint(Window, &ps); } break; } return DefWindowProc(Window, Message, WParam, LParam); } int CALLBACK WinMain( HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR lpCmdLine, int nShowCmd ) { WNDCLASS WindowClass = {}; WindowClass.style = CS_HREDRAW | CS_VREDRAW; WindowClass.lpfnWndProc = MainWindowCallback; WindowClass.hInstance = Instance; WindowClass.lpszMenuName = "mainMenu"; WindowClass.lpszClassName = "MainWindow"; RegisterClass(&WindowClass); HWND Window = CreateWindowEx( 0, WindowClass.lpszClassName, "Win32 Test App", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, Instance, 0 ); if (Window == nullptr) { printf("Error CreateWindow()\n"); exit(1); } ShowWindow(Window, nShowCmd); MSG Message; while ( GetMessage(&Message, 0, 0, 0) > 0 ) { TranslateMessage(&Message); DispatchMessage(&Message); } }
问题原因
- 无效菜单引用:窗口类中指定了
lpszMenuName = "mainMenu",但无对应菜单资源,系统会为不存在的菜单栏预留顶部空间,导致工具栏被向下挤压。 - 未处理
WM_SIZE消息:窗口创建或尺寸改变时,未重新调整工具栏的位置与大小,无法自适应客户区变化。
修复方案
1. 移除无效菜单引用
在WNDCLASS初始化中删除WindowClass.lpszMenuName = "mainMenu";,避免系统预留无效的菜单栏空间。
2. 保存工具栏句柄并处理WM_SIZE消息
- 替换无用的
TreeViewHandle为全局工具栏句柄:HWND g_hWndToolbar = NULL; - 在
WM_CREATE中保存工具栏句柄:case WM_CREATE: { g_hWndToolbar = MainWindowToolbar(Window); } break; - 修改
WM_SIZE消息处理,确保工具栏贴顶并铺满客户区宽度:case WM_SIZE: { if (g_hWndToolbar != NULL) { RECT clientRect; GetClientRect(Window, &clientRect); // 让工具栏自动计算合适高度 SendMessage(g_hWndToolbar, TB_AUTOSIZE, 0, 0); // 获取工具栏实际高度 RECT toolbarRect; GetWindowRect(g_hWndToolbar, &toolbarRect); int toolbarHeight = toolbarRect.bottom - toolbarRect.top; // 移动并调整工具栏大小 MoveWindow(g_hWndToolbar, 0, 0, clientRect.right, toolbarHeight, TRUE); } } break;
3. 初始化通用控件
在WinMain开头添加InitCommonControls();,确保工具栏等通用控件正确加载:
int CALLBACK WinMain( HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR lpCmdLine, int nShowCmd ) { InitCommonControls(); // 添加这一行 // 剩余代码不变 }
修复后的完整代码
#include <Windows.h> #include <CommCtrl.h> #include <cstdio> HIMAGELIST g_hImageList = NULL; const int IDM_NEW = 201; const int IDM_OPEN = 202; const int IDM_SAVE = 203; HWND g_hWndToolbar = NULL; // 全局工具栏句柄 HWND MainWindowToolbar( HWND Window ) { const int ImageListID = 0; const int numButtons = 3; const int bitmapSize = 16; const DWORD buttonStyles = BTNS_AUTOSIZE; // 创建工具栏 HWND hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | TBSTYLE_WRAPABLE, 0, 0, 0, 0, Window, NULL, GetModuleHandle(NULL), NULL); if (hWndToolbar == NULL) return NULL; // 创建图像列表 g_hImageList = ImageList_Create(bitmapSize, bitmapSize, ILC_COLOR16 | ILC_MASK, numButtons, 0); // 设置图像列表 SendMessage(hWndToolbar, TB_SETIMAGELIST, (WPARAM)ImageListID, (LPARAM)g_hImageList); // 加载标准按钮图像 SendMessage(hWndToolbar, TB_LOADIMAGES, (WPARAM)IDB_STD_SMALL_COLOR, (LPARAM)HINST_COMMCTRL); // 初始化按钮信息 TBBUTTON tbButtons[numButtons] = { { MAKELONG(STD_FILENEW, ImageListID), IDM_NEW, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"New" }, { MAKELONG(STD_FILEOPEN, ImageListID), IDM_OPEN, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"Open"}, { MAKELONG(STD_FILESAVE, ImageListID), IDM_SAVE, 0, buttonStyles, {0}, 0, (INT_PTR)L"Save"} }; // 添加按钮 SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); SendMessage(hWndToolbar, TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)&tbButtons); // 自动调整大小并显示 SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0); ShowWindow(hWndToolbar, TRUE); return hWndToolbar; } LRESULT CALLBACK MainWindowCallback( HWND Window, UINT Message, WPARAM WParam, LPARAM LParam ) { switch(Message) { case WM_CREATE: { g_hWndToolbar = MainWindowToolbar( Window ); } break; case WM_SIZE: { if (g_hWndToolbar != NULL) { RECT clientRect; GetClientRect(Window, &clientRect); SendMessage(g_hWndToolbar, TB_AUTOSIZE, 0, 0); RECT toolbarRect; GetWindowRect(g_hWndToolbar, &toolbarRect); int toolbarHeight = toolbarRect.bottom - toolbarRect.top; MoveWindow(g_hWndToolbar, 0, 0, clientRect.right, toolbarHeight, TRUE); } } break; case WM_DESTROY: { PostQuitMessage(0); } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(Window, &ps); FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1)); EndPaint(Window, &ps); } break; } return DefWindowProc(Window, Message, WParam, LParam); } int CALLBACK WinMain( HINSTANCE Instance, HINSTANCE PrevInstance, LPSTR lpCmdLine, int nShowCmd ) { InitCommonControls(); // 初始化通用控件 WNDCLASS WindowClass = {}; WindowClass.style = CS_HREDRAW | CS_VREDRAW; WindowClass.lpfnWndProc = MainWindowCallback; WindowClass.hInstance = Instance; WindowClass.lpszClassName = "MainWindow"; RegisterClass(&WindowClass); HWND Window = CreateWindowEx( 0, WindowClass.lpszClassName, "Win32 Test App", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, Instance, 0 ); if (Window == nullptr) { printf("Error CreateWindow()\n"); exit(1); } ShowWindow(Window, nShowCmd); MSG Message; while ( GetMessage(&Message, 0, 0, 0) > 0 ) { TranslateMessage(&Message); DispatchMessage(&Message); } }
内容的提问来源于stack exchange,提问作者Commodore63
相关产品推荐
相关产品推荐

