VC自绘按钮的实现(NO MFC)

来源:互联网 发布:淘宝大衣比较好的店铺 编辑:程序博客网 时间:2024/05/23 11:56

使用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消息