Windows 95 引入的 ReBar/Cool Bar 控制項(位於 Comctl32.dll)讓工具列從立體凸塊變為扁平化,滑鼠懸停時自動浮現立體邊框,大幅提升視覺質感。MFC 封裝的 CToolBar 早期版本不支援此風格,需直接呼叫 Win32 API 建立 TOOLBARCLASSNAME 視窗。本文提供完整步驟與程式碼,示範如何在 VC++ 6.0/VS2008+ 專案中手工建立、配置圖示、處理按鈕點擊。
ICC_COOL_CLASSES | ICC_BAR_CLASSES)。CreateWindowEx 建立 WS_EX_TOOLWINDOW | TBSTYLE_FLAT 風格的工具列視窗。HIMAGELIST,載入位圖資源(ImageList_Create/Add)。TB_SETIMAGELIST 將圖示清單關聯到工具列。TBBUTTON 陣列,TB_ADDBUTTONS 加入按鈕。ShowWindow 顯示工具列。OnCommand 處理 WM_COMMAND 回應按鈕點擊。CWinApp::InitInstance 或主視窗 OnCreate)INITCOMMONCONTROLSEX icex = { sizeof(icex) };
icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES;
InitCommonControlsEx(&icex);
OnCreate)HWND hToolBar = CreateWindowEx(
WS_EX_TOOLWINDOW, // 擴充風格
TOOLBARCLASSNAME, // 類別名
NULL, // 視窗標題
WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | CCS_NODIVIDER,
0, 0, 0, 0, // 位置/大小稍後調整
m_hWnd, // 父視窗
(HMENU)IDC_MAIN_TOOLBAR, // 控制項 ID
AfxGetInstanceHandle(), NULL);
if (!hToolBar) return -1;
// 假設工具列位圖資源 IDB_BITMAP_TOOLBAR,每顆圖示 24x22
HIMAGELIST hImgList = ImageList_Create(24, 22, ILC_COLOR32 | ILC_MASK, 0, 4);
HBITMAP hBmp = LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP_TOOLBAR));
ImageList_Add(hImgList, hBmp, NULL);
DeleteObject(hBmp); // ImageList 內部已複製,原位圖可釋放
SendMessage(hToolBar, TB_SETIMAGELIST, 0, (LPARAM)hImgList);
const int BTN_COUNT = 5;
TBBUTTON tb[BTN_COUNT] = {0};
for (int i = 0; i < BTN_COUNT; ++i)
{
tb[i].iBitmap = i; // ImageList 索引
tb[i].idCommand = ID_TOOL_BTN_START + i; // 命令 ID
tb[i].fsState = TBSTATE_ENABLED;
tb[i].fsStyle = TBSTYLE_BUTTON;
tb[i].dwData = 0;
tb[i].iString = -1; // 無文字標籤
}
SendMessage(hToolBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
SendMessage(hToolBar, TB_ADDBUTTONS, BTN_COUNT, (LPARAM)tb);
// 讓工具列自動計算理想大小
RECT rc; SendMessage(hToolBar, TB_AUTOSIZE, 0, (LPARAM)&rc);
SetWindowPos(hToolBar, NULL, 0, 0, rc.right, rc.bottom, SWP_NOZORDER | SWP_NOMOVE);
ShowWindow(hToolBar, SW_SHOW);
BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)
{
switch (LOWORD(wParam))
{
case ID_TOOL_BTN_START + 0: AfxMessageBox(L"按鈕 1 被點擊"); break;
case ID_TOOL_BTN_START + 1: AfxMessageBox(L"按鈕 2 被點擊"); break;
case ID_TOOL_BTN_START + 2: AfxMessageBox(L"按鈕 3 被點擊"); break;
// ...
}
return CFrameWnd::OnCommand(wParam, lParam);
}
| 需求 | 解決方案 |
|---|---|
| 按鈕帶文字標籤 | TBBUTTON::iString 指向 TB_ADDSTRING 加入的字串索引;或用 TBSTYLE_AUTOSIZE 讓按鈕自適應寬度。 |
| 下拉式按鈕 | fsStyle = TBSTYLE_DROPDOWN,處理 TBN_DROPDOWN 通知顯示選單。 |
| 分隔線 | fsStyle = TBSTYLE_SEP,iBitmap 設寬度(像素)。 |
| 工具列鎖定/解鎖拖曳 | 切換 CCS_NOPARENTALIGN | CCS_NOMOVEY 風格,配合 TB_SETSTYLE。 |
| 高 DPI 下圖示模糊 | 使用 ILC_COLOR32 + 多解析度位圖(或 SVG 轉 PNG),ImageList_SetIconSize 設定目標尺寸。 |
新版 MFC CMFCToolBar 內建支援 Office 2007/2010/2013 風格,只需:
// 在 CMainFrame::OnCreate
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP)
|| !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
return -1;
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
若維護舊專案必須用 SDK 方式,本文範例可直接套用;新專案建議改用 CMFCToolBar 享受現代化主題、自動佈局、觸控優化等優勢。
透過 CreateWindowEx + TOOLBARCLASSNAME + ImageList 的經典組合,即可在任何 VC++ 專案中打造出具備懸停浮現效果的扁平化工具列。理解底層訊息流程(TB_ADDBUTTONS、WM_COMMAND 轉發)有助於除錯與客製化;若專案允許,升級至 CMFCToolBar 可大幅減少樣板程式碼並獲得持續維護的現代 UI 支援。