使用MFC的CBitmapButton或者CButtonST等类很容易在按钮上画出位图+文字的Button。但是如果不使用MFC该怎么画呢?下面就是纯粹的SDK做的位图+文字的Button:
// OwnerDrawBtn.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "resource.h"
#define ICON_HEIGHT 32
#define ICON_WIDTH 32
static HINSTANCE hInst; // current instance
static HICON hIcon = NULL;
static void InitializeDialog(HWND hwnd);
static void DrawTheIcon(HWND hButtonWnd, HDC* dc, BOOL bHasTitle, RECT* rpItem, RECT* rpTitle, BOOL bIsPressed, BOOL bIsDisabled);
static void PrepareImageRect(HWND hButtonWnd, BOOL bHasTitle, RECT* rpItem, RECT* rpTitle, BOOL bIsPressed, DWORD dwWidth, DWORD dwHeight, RECT* rpImage);
LRESULT CALLBACK DialogFunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
static char szAppName[] = "OWNERDRAWBUTTON";
HWND hwnd;
MSG msg;
WNDCLASSEX wndclass;
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = DialogFunc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = DLGWINDOWEXTRA;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wndclass.lpszMenuName = (LPCSTR)szAppName;
wndclass.lpszClassName = szAppName;
wndclass.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
RegisterClassEx(&wndclass);
hInst = hInstance; // get current instance.
hwnd = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), GetDesktopWindow(), (DLGPROC)DialogFunc);
ShowWindow(hwnd, nCmdShow);
while (GetMessage(&msg, NULL, 0, 0))
{
if (!IsWindow(hwnd) || !IsDialogMessage(hwnd, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
LRESULT CALLBACK DialogFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_INITDIALOG:
InitializeDialog(hwnd);
break;
case WM_CREATE:
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
::EndDialog(hwnd, LOWORD(wParam));
::PostQuitMessage(0);
break;
default:
break;
}
break;
case WM_DRAWITEM:
{
// draw the owner draw button
LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) lParam;
if(lpDIS->CtlID != IDC_BMPBTN)
{
return (0);
}
HDC dc = lpDIS->hDC;
// button state
BOOL bIsPressed = (lpDIS->itemState & ODS_SELECTED);
BOOL bIsFocused = (lpDIS->itemState & ODS_FOCUS);
BOOL bIsDisabled = (lpDIS->itemState & ODS_DISABLED);
RECT itemRect = lpDIS->rcItem;
::SetBkMode(dc, TRANSPARENT);
if (bIsFocused)
{
HBRUSH br = CreateSolidBrush(RGB(0,0,0));
::FrameRect(dc, &itemRect, br);
::InflateRect(&itemRect, -1, -1);
::DeleteObject(br);
}
COLORREF crColor = GetSysColor(COLOR_BTNFACE);
HBRUSH brBackground = CreateSolidBrush(crColor);
::FillRect(dc, &itemRect, brBackground);
::DeleteObject(brBackground);
// Draw pressed button
if (bIsPressed)
{
HBRUSH brBtnShadow = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
::FrameRect(dc, &itemRect, brBtnShadow);
::DeleteObject(brBtnShadow);
}
else // ...else draw non pressed button
{
UINT uState = DFCS_BUTTONPUSH | ((bIsPressed) ? DFCS_PUSHED : 0);
::DrawFrameControl(dc, &itemRect, DFC_BUTTON, uState);
}
// Read the button's title
char sTitle[100];
::GetWindowText(::GetDlgItem(hwnd, IDC_BMPBTN), sTitle, 100);
RECT captionRect = lpDIS->rcItem;
BOOL bHasTitle = (sTitle[0] != '\0');
DrawTheIcon(::GetDlgItem(hwnd, IDC_BMPBTN), &dc, bHasTitle, &lpDIS->rcItem, &captionRect, bIsPressed, bIsDisabled);
if (bHasTitle)
{// Draw the button's title
// Center text
RECT centerRect = captionRect;
::DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CENTER | DT_CALCRECT);
LONG captionRectWidth = captionRect.right - captionRect.left;
LONG captionRectHeight = captionRect.bottom - captionRect.top;
LONG centerRectWidth = centerRect.right - centerRect.left;
LONG centerRectHeight = centerRect.bottom - centerRect.top;
::OffsetRect(&captionRect, (centerRectWidth - captionRectWidth)/2, (centerRectHeight - captionRectHeight)/2);
::SetBkMode(dc, TRANSPARENT);
if (bIsDisabled)
{
::OffsetRect(&captionRect, 1, 1);
::SetTextColor(dc, ::GetSysColor(COLOR_3DHILIGHT));
::DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CENTER);
::OffsetRect(&captionRect, -1, -1);
::SetTextColor(dc, ::GetSysColor(COLOR_3DSHADOW));
::DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CENTER);
}
else
{
::SetTextColor(dc, ::GetSysColor(COLOR_BTNTEXT));
::SetBkColor(dc, ::GetSysColor(COLOR_BTNFACE));
::DrawText(dc, sTitle, -1, &captionRect, DT_WORDBREAK | DT_CENTER);
}
// Draw the focus rect
if (bIsFocused)
{
RECT focusRect = itemRect;
::InflateRect(&focusRect, -3, -3);
::DrawFocusRect(dc, &focusRect);
}
return (TRUE);
} // End if
break;
}
case WM_DESTROY:
::PostQuitMessage(0);
return FALSE;
}
return FALSE;
}
void InitializeDialog(HWND hwnd)
{
hIcon = ::LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1));
::SetFocus(::GetDlgItem(hwnd, IDC_BMPBTN));
}
static void DrawTheIcon(HWND hButtonWnd, HDC* dc, BOOL bHasTitle, RECT* rpItem, RECT* rpTitle, BOOL bIsPressed, BOOL bIsDisabled)
{
RECT rImage;
PrepareImageRect(hButtonWnd, bHasTitle, rpItem, rpTitle, bIsPressed, ICON_WIDTH, ICON_HEIGHT, &rImage);
// Ole'!
::DrawState(*dc,
NULL,
NULL,
(LPARAM)hIcon,
0,
rImage.left,
rImage.top,
(rImage.right - rImage.left),
(rImage.bottom - rImage.top),
(bIsDisabled ? DSS_DISABLED : DSS_NORMAL) | DST_ICON);
}
static void PrepareImageRect(HWND hButtonWnd, BOOL bHasTitle, RECT* rpItem, RECT* rpTitle, BOOL bIsPressed, DWORD dwWidth, DWORD dwHeight, RECT* rpImage)
{
RECT rBtn;
::CopyRect(rpImage, rpItem);
::GetClientRect(hButtonWnd, &rBtn);
if (bHasTitle == FALSE)
{
// Center image horizontally
LONG rpImageWidth = rpImage->right - rpImage->left;
rpImage->left += ((rpImageWidth - (long)dwWidth)/2);
}
else
{
// Image must be placed just inside the focus rect
LONG rpTitleWidth = rpTitle->right - rpTitle->left;
rpTitle->right = rpTitleWidth - dwWidth - 30;
rpTitle->left = 30;
rpImage->left = rBtn.right - dwWidth - 30;
// Center image vertically
LONG rpImageHeight = rpImage->bottom - rpImage->top;
rpImage->top += ((rpImageHeight - (long)dwHeight)/2);
}
}
关键点:必须在BUTTON的属性中设置:Owner draw,这样才会产生WM_DRAWITEM消息