ATL项目中按钮控件颜色修改问题求助
Hey there! Let's work through how to color your ATL button controls without leaning on MFC functions—good news, that Q173974 solution isn't your only option. Here are practical, MFC-free approaches tailored for ATL:
First off, yes, you absolutely can style ATL button controls without using MFC—no need to rely on that single KB article. Let's break down three reliable methods:
1. Subclass the ATL Button for Custom Drawing
ATL makes subclassing controls straightforward. Create a custom CWindowImpl-derived class for your button, then handle WM_PAINT to draw it exactly how you want:
class CColoredButton : public CWindowImpl<CColoredButton, CButton> { public: BEGIN_MSG_MAP(CColoredButton) MESSAGE_HANDLER(WM_PAINT, OnPaint) END_MSG_MAP() LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) { PAINTSTRUCT ps; HDC hdc = BeginPaint(&ps); RECT rc; GetClientRect(&rc); // Fill button background with your desired color HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 255)); FillRect(hdc, &rc, hBrush); DeleteObject(hBrush); // Draw button text (adjust alignment/colors as needed) SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, RGB(255, 255, 255)); CString strText; GetWindowText(strText); DrawText(hdc, strText, strText.GetLength(), &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE); EndPaint(&ps); return 0; } };
Then attach this subclass to your button in your ATL window's initialization (like OnInitDialog):
CColoredButton m_btnCustom; m_btnCustom.SubclassWindow(GetDlgItem(IDC_YOUR_BUTTON));
2. Handle WM_CTLCOLORBTN in the Parent Window
If you don't want to subclass, you can catch the WM_CTLCOLORBTN message in your main ATL window (this message is sent to the button's parent). This is great for quick color tweaks:
BEGIN_MSG_MAP(CYourATLWindow) // ... other message handlers MESSAGE_HANDLER(WM_CTLCOLORBTN, OnCtlColorBtn) END_MSG_MAP() HBRUSH OnCtlColorBtn(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { HWND hBtn = (HWND)lParam; if (hBtn == GetDlgItem(IDC_YOUR_BUTTON)) { HDC hdcBtn = (HDC)wParam; // Set text color and transparent background for text SetTextColor(hdcBtn, RGB(255, 255, 255)); SetBkMode(hdcBtn, TRANSPARENT); // Return a persistent brush for the button background static HBRUSH hBtnBrush = CreateSolidBrush(RGB(0, 0, 255)); return hBtnBrush; } bHandled = FALSE; // Let default logic handle other buttons return NULL; }
Pro tip: Keep the brush alive (don't delete it right away) — Windows may reuse it for subsequent repaints.
3. Use Owner-Draw Buttons
For full control over button states (pressed, focused, hover), set the button to BS_OWNERDRAW style and handle WM_DRAWITEM in the parent window:
- First, enable owner-draw style (either in the resource editor or via code):
HWND hBtn = GetDlgItem(IDC_YOUR_BUTTON); SetWindowLongPtr(hBtn, GWL_STYLE, GetWindowLongPtr(hBtn, GWL_STYLE) | BS_OWNERDRAW);
- Add the
WM_DRAWITEMhandler to your ATL window:
MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem) LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; if (lpdis->CtlID == IDC_YOUR_BUTTON) { HDC hdc = lpdis->hDC; RECT rc = lpdis->rcItem; // Adjust background color based on button state COLORREF bgColor = RGB(0, 0, 255); if (lpdis->itemState & ODS_SELECTED) bgColor = RGB(0, 0, 200); // Darker blue when pressed else if (lpdis->itemState & ODS_FOCUS) bgColor = RGB(0, 0, 220); // Slightly darker when focused HBRUSH hBrush = CreateSolidBrush(bgColor); FillRect(hdc, &rc, hBrush); DeleteObject(hBrush); // Draw focus rectangle if needed if (lpdis->itemState & ODS_FOCUS) DrawFocusRect(hdc, &rc); // Draw button text SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, RGB(255, 255, 255)); CString strText; GetDlgItemText(lpdis->CtlID, strText); DrawText(hdc, strText, strText.GetLength(), &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE); return 0; } bHandled = FALSE; return 0; }
All these methods avoid MFC entirely, so you won't hit those annoying function definition conflicts. Pick the approach that fits your needs: subclassing for reusable components, WM_CTLCOLORBTN for quick changes, or owner-draw for full state control.
内容的提问来源于stack exchange,提问作者user2958976

