按鈕是最基礎的交互控件。MFC CButton 統一封裝普通按鈕、複選框、單選按鈕三大類九種風格,支持自動狀態切換、三態邏輯、自繪、位圖按鈕及完整消息處理。本文系統講解風格對比、創建參數、狀態控制、自繪實現及 CBitmapButton 使用。
BOOL Create(LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
| 風格 | 類型 | 視覺特徵 | 自動狀態 | 典型用途 | |
|---|---|---|---|---|---|
BS_PUSHBUTTON | 普通按鈕 | 矩形,點擊凹陷 | 否 | 確定、取消、執行動作 | |
BS_DEFPUSHBUTTON | 默認按鈕 | 粗黑邊框,Enter 觸發 | 否 | 對話框默認確認鍵 | |
BS_CHECKBOX | 複選框 | 小方框+右側文本 | 否 | 獨立開關選項 | |
BS_AUTOCHECKBOX | 自動複選框 | 方框+勾選標記 | 是 (點擊切換) | 標準複選框 | |
BS_RADIOBUTTON | 單選按鈕 | 小圓圈+右側文本 | 否 | 互斥組項目 | |
BS_AUTORADIOBUTTON | 自動單選按鈕 | 圓圈+實心點 | 是 (自動互斥) | 標準單選組 | |
BS_3STATE | 三態複選框 | 方框+勾選/灰色/空 | 否 | 部分選中狀態 | |
BS_AUTO3STATE | 自動三態複選框 | 方框+三態循環 | 是 (循環切換) | 父子節點關聯 | |
BS_OWNERDRAW | 自繪按鈕 | 完全自定義繪製 | 否 | 非標準外觀、動畫按鈕 | |
BS_LEFTTEXT | 文本左側 (輔助) | 文本在圖標/框左側 | - | 右對齊佈局 | |
BS_BITMAP | 位圖按鈕 (配合 CBitmapButton) | 顯示位圖 | - | 圖標按鈕、工具欄風格 |
lpszCaption:按鈕顯示文本 (自繪/位圖按鈕可為空)dwStyle:WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_XXXrect:位置大小 (對話框單位為對話框單位,非像素)pParentWnd:父窗口指針nID:控件 ID (命令消息識別用)| 操作 | 函數 | 適用風格 |
|---|---|---|
| 獲取/設置勾選狀態 | GetCheck() / SetCheck(int) | CHECKBOX, RADIO, 3STATE |
| 獲取/設置按鈕文本 | GetWindowText() / SetWindowText() | 所有 |
| 啟用/禁用 | EnableWindow(BOOL) | 所有 |
| 設置/獲取按鈕狀態 | SetButtonStyle(UINT) / GetButtonStyle() | 所有 |
| 設置/獲取圖標 | SetIcon(HICON) / GetIcon() | BS_ICON (需風格) |
| 設置/獲取位圖 | SetBitmap(HBITMAP) / GetBitmap() | BS_BITMAP |
| 設置/獲取游標 | SetCursor(HCURSOR) / GetCursor() | 所有 |
0:未選中 (BST_UNCHECKED)1:選中 (BST_CHECKED)2:不確定/灰色 (BST_INDETERMINATE) — 僅三態風格核心規則:同一父窗口中,連續的 BS_AUTORADIOBUTTON 自動形成互斥組。組別由 WS_GROUP 風格分隔。
// 第1組:性別
btnMale.Create(_T("男"), WS_CHILD|WS_VISIBLE|WS_GROUP|BS_AUTORADIOBUTTON, rect1, this, IDC_MALE);
btnFemale.Create(_T("女"), WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON, rect2, this, IDC_FEMALE);
// 第2組:會員等級 (WS_GROUP 斷開上一組)
btnVip1.Create(_T("銀卡"), WS_CHILD|WS_VISIBLE|WS_GROUP|BS_AUTORADIOBUTTON, rect3, this, IDC_VIP1);
btnVip2.Create(_T("金卡"), WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON, rect4, this, IDC_VIP2);
btnVip3.Create(_T("鉆石"), WS_CHILD|WS_VISIBLE|BS_AUTORADIOBUTTON, rect5, this, IDC_VIP3);
class COwnerDrawBtn : public CButton {
DECLARE_DYNAMIC(COwnerDrawBtn)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
};
void COwnerDrawBtn::DrawItem(LPDRAWITEMSTRUCT lpDIS) {
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
CRect rect(lpDIS->rcItem);
UINT state = lpDIS->itemState;
// 1. 繪製背景
COLORREF bg = (state & ODS_SELECTED) ? RGB(0,120,215) : RGB(240,240,240);
pDC->FillSolidRect(rect, bg);
// 2. 繪製邊框
if (state & ODS_FOCUS) {
pDC->DrawFocusRect(rect);
}
CPen pen(PS_SOLID, 1, (state & ODS_SELECTED) ? RGB(0,80,160) : RGB(180,180,180));
CPen* pOld = pDC->SelectObject(&pen);
pDC->Rectangle(rect);
pDC->SelectObject(pOld);
// 3. 繪製文本
CString text;
GetWindowText(text);
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor((state & ODS_SELECTED) ? RGB(255,255,255) : RGB(0,0,0));
pDC->DrawText(text, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
// 頭文件
COwnerDrawBtn m_btnCustom;
// OnInitDialog
m_btnCustom.SubclassDlgItem(IDC_CUSTOM_BTN, this);
// 確保資源編輯器中按鈕風格設置為 Owner Draw
class CMyDialog : public CDialog {
CBitmapButton m_btnBitmap;
public:
BOOL OnInitDialog() {
CDialog::OnInitDialog();
// 關鍵:AutoLoad 自動關聯 4 狀態位圖
// 位圖資源 ID: IDB_BTN_NORMAL, IDB_BTN_PUSHED, IDB_BTN_FOCUS, IDB_BTN_DISABLED
// 或單一位圖 IDB_BTN_ALL (包含4狀態)
m_btnBitmap.AutoLoad(IDC_BITMAP_BTN, this);
// 手動指定位圖 (可選)
// m_btnBitmap.LoadBitmaps(IDB_NORMAL, IDB_PUSHED, IDB_FOCUS, IDB_DISABLED);
// 設置大小 (可選,默認按位圖尺寸)
m_btnBitmap.SizeToContent();
return TRUE;
}
};
ON_BN_CLICKED(IDC_BTN, OnBtnClicked) // 點擊 (所有按鈕)
ON_BN_DOUBLECLICKED(IDC_BTN, OnBtnDblClk) // 雙擊
ON_BN_SETFOCUS(IDC_BTN, OnBtnSetFocus) // 獲得焦點
ON_BN_KILLFOCUS(IDC_BTN, OnBtnKillFocus) // 失去焦點
ON_BN_DISABLE(IDC_BTN, OnBtnDisable) // 禁用狀態 (罕用)
WS_GROUP 分隔,導致所有單選按鈕成一組BS_AUTOCHECKBOX 才有點擊切換效果BS_AUTO3STATE 循環順序 0→1→2→0,業務邏輯需明確 2 的含義DrawItemAutoLoad 或 LoadBitmapsBS_BITMAP/BS_ICON 風格下文本不顯示,需自繪實現圖文混排本文整理自 MFC 經典技術文檔,適用於 VC6~VS2022 所有版本。