Win32 Rebar控件显示异常:Toolbar底部出现意外抓手如何解决?
Win32 Toolbar嵌入Rebar后底部出现意外抓手的解决方法
我开发了一个标准Win32应用,包含Toolbar和Rebar控件。先创建作为主窗口子控件的Toolbar,再创建Rebar并将Toolbar加入其band中。但Toolbar底部出现了意外的抓手(如图所示):
以下是我的创建代码(复制自MSDN):
HIMAGELIST g_hImageList = NULL; HWND CreateSimpleToolbar(HWND hWndParent) { // Declare and initialize local constants. const int ImageListID = 0; const int numButtons = 3; const int bitmapSize = 16; const DWORD buttonStyles = BTNS_AUTOSIZE; // Create the toolbar. HWND hWndToolbar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL, WS_CHILD | TBSTYLE_FLAT | TBSTYLE_LIST, 0, 0, 0, 0, hWndParent, NULL, hInst, 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), 100, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"Back"}, { MAKELONG(STD_FILEOPEN, ImageListID), 101, TBSTATE_ENABLED, buttonStyles, {0}, 0, (INT_PTR)L"Forward"}, { MAKELONG(STD_FILESAVE, ImageListID), 102, 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; } #define NUMBUTTONS 3 HWND CreateRebar(HWND hwndOwner, HWND hwndNavbar) { // Check parameters. if ((hwndNavbar == NULL)) { return NULL; } // Initialize common controls. INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES; InitCommonControlsEx(&icex); // Create the rebar. HWND hwndRebar = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | RBS_VARHEIGHT | CCS_NODIVIDER | RBS_BANDBORDERS, 0, 0, 0, 0, hwndOwner, NULL, hInst, // global instance handle NULL); if (!hwndRebar) { return NULL; } // Initialize band info used by both bands. REBARBANDINFO rbBand = { REBARBANDINFOA_V3_SIZE }; rbBand.fMask = RBBIM_STYLE // fStyle is valid. | RBBIM_TEXT // lpText is valid. | RBBIM_CHILD // hwndChild is valid. | RBBIM_CHILDSIZE // child size members are valid. | RBBIM_SIZE; // cx is valid rbBand.fStyle = RBBS_CHILDEDGE | RBBS_GRIPPERALWAYS; // Get the height of the toolbar. DWORD dwBtnSize = (DWORD)SendMessage(hwndNavbar, TB_GETBUTTONSIZE, 0, 0); // Set values unique to the band with the toolbar. rbBand.lpText = LPWSTR(""); rbBand.hwndChild = hwndNavbar; rbBand.cyChild = LOWORD(dwBtnSize); rbBand.cxMinChild = NUMBUTTONS * HIWORD(dwBtnSize); rbBand.cyMinChild = LOWORD(dwBtnSize); // The default width is the width of the buttons. rbBand.cx = 0; // Add the band that has the toolbar. if (!SendMessage(hwndRebar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand)) { MessageBox(NULL, _T("Could not create band!"), _T("pXview"), NULL); } return (hwndRebar); }
控件创建时机为窗口显示并更新后,代码如下:
HWND toolbar = CreateSimpleToolbar(hWnd); CreateRebar(hWnd, toolbar);
我尝试修改样式、调整Rebar band的尺寸与位置等操作,均未能解决问题。
问题原因分析
- Toolbar父窗口变更冲突:先将Toolbar创建为主窗口子控件并调用
TB_AUTOSIZE、ShowWindow,后续加入Rebar时父窗口切换为Rebar,残留的布局状态导致显示异常。 - Rebar Band配置错误:
RBBS_GRIPPERALWAYS样式强制显示抓手,且用TB_GETBUTTONSIZE获取的按钮尺寸代替Toolbar完整高度,导致band高度不足,抓手被挤压到Toolbar区域。 - 重复初始化公共控件:
CreateRebar内重复调用InitCommonControlsEx,可能导致控件样式异常。
修复方案
1. 调整Toolbar创建逻辑
移除提前的TB_AUTOSIZE和ShowWindow调用,让Rebar管理Toolbar的显示与尺寸:
HWND CreateSimpleToolbar(HWND hWndParent) { // ... 原有常量、创建Toolbar、图像列表、按钮添加逻辑不变 ... // 移除以下两行代码 // SendMessage(hWndToolbar, TB_AUTOSIZE, 0, 0); // ShowWindow(hWndToolbar, TRUE); return hWndToolbar; }
2. 修正Rebar Band配置
- 移除
RBBS_GRIPPERALWAYS样式,避免强制显示抓手;如需保留可拖动抓手,改用RBBS_GRIPPER(仅当band可拖动时显示)。 - 用
TB_GETHEIGHT获取Toolbar完整高度,替代按钮尺寸:
HWND CreateRebar(HWND hwndOwner, HWND hwndNavbar) { // ... 参数检查逻辑不变 ... // 将InitCommonControlsEx移到程序启动初期,避免重复初始化 // 移除此处的INITCOMMONCONTROLSEX代码块 // ... 创建Rebar窗口逻辑不变 ... // 初始化band信息 REBARBANDINFO rbBand = { REBARBANDINFOW_V3_SIZE }; // Unicode环境下使用宽字符版本 rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE; rbBand.fStyle = RBBS_CHILDEDGE; // 移除RBBS_GRIPPERALWAYS // 获取Toolbar完整高度 int toolbarHeight = (int)SendMessage(hwndNavbar, TB_GETHEIGHT, 0, 0); // 设置band参数 rbBand.hwndChild = hwndNavbar; rbBand.cyChild = toolbarHeight; rbBand.cyMinChild = toolbarHeight; rbBand.cx = (int)SendMessage(hwndNavbar, TB_GETMAXSIZE, 0, 0); // 自动适配Toolbar宽度 // ... 插入band逻辑不变 ... return (hwndRebar); }
3. 调整控件创建流程
确保InitCommonControlsEx在程序启动时只调用一次,比如在WinMain开头:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES; InitCommonControlsEx(&icex); // ... 主窗口创建、消息循环等逻辑 ... // 创建控件 HWND toolbar = CreateSimpleToolbar(hWnd); HWND rebar = CreateRebar(hWnd, toolbar); SendMessage(rebar, RB_AUTOSIZE, 0, 0); // 让Rebar自动调整大小 // ... 消息循环 ... }
内容的提问来源于stack exchange,提问作者user21591956
相关产品推荐
相关产品推荐

