📄 custombutton.cpp
字号:
#include "CustomButton.h"
IMPLEMENT_DYNAMIC(CCustomButton, CButton)
/////////////////////////////////////////////////////////////////////////////
// CCustomButton
CCustomButton::CCustomButton()
{
m_crTxtIdle=::GetSysColor(COLOR_BTNTEXT);
m_crBkgIdle=::GetSysColor(COLOR_BTNFACE);
m_crTxtPressed=m_crTxtIdle;
m_crBkgPressed=m_crBkgIdle;
m_crFrame=m_crTxtIdle;
m_crHGStart=RGB(0, 0, 0);
m_crHGEnd=RGB(255, 255, 255);
m_bPressed=false;
m_bFlat=true;
m_bTransparent=false;
m_bHGradient=false;
m_bIsGroup=false;
m_hBmpActive=m_hBmpInactive=NULL;
m_dwBmpW=m_dwBmpH=0;
m_hCustomFont=NULL;
m_ctType=btCustomButton;
RegisterCustomClass();
}
//////////////////////////////////////////////////////////////
CCustomButton::~CCustomButton()
{
if(m_hBmpActive != NULL)
{
DeleteObject(m_hBmpActive);
}
if(m_hBmpInactive != NULL)
{
DeleteObject(m_hBmpInactive);
}
m_DrawDC.SelectObject(m_hOldDCBmp);
DeleteObject(m_hOldDCBmp);
if(m_hCustomFont != NULL)
{
DeleteObject(m_hCustomFont);
}
}
//////////////////////////////////////////////////////////////////////////
bool CCustomButton::RegisterCustomClass()
{
WNDCLASS wndcls;
HINSTANCE hInst;
hInst = AfxGetInstanceHandle();
if(!(::GetClassInfo(hInst, _T("CustomButtonClass"), &wndcls)))
{
// otherwise we need to register a new class
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = NULL;
wndcls.hCursor = NULL;
wndcls.hbrBackground = (HBRUSH)::GetStockObject(NULL_BRUSH);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = _T("CustomButtonClass");
if(FALSE == AfxRegisterClass(&wndcls))
{
#ifdef _DEBUG
OutputDebugString(_T("Failed to register class for Custom_button"));
#endif
return false;
}
}
return true;
}
//////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CCustomButton, CButton)
//{{AFX_MSG_MAP(CCustomButton)
// NOTE - the ClassWizard will add and remove mapping macros here.
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_MESSAGE(BM_SETCHECK, OnBMSetCheck)
ON_MESSAGE(BM_GETCHECK, OnBMGetCheck)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////////
LRESULT CCustomButton::OnBMSetCheck(WPARAM wParam, LPARAM lParam)
{
//if radio
if(m_ctType == btCustomRadio || m_ctType == btCustomCheckBox)
{
if(wParam == BST_CHECKED)
{
m_bPressed=true;
SetWindowText(m_strActiveCaption);
}
else
{
m_bPressed=false;
SetWindowText(m_strCaption);
}
Invalidate();
}
//processed
return 0;
}
//////////////////////////////////////////////////////////////////////////
LRESULT CCustomButton::OnBMGetCheck(WPARAM wParam, LPARAM lParam)
{
if(m_bPressed == true)
{
return BST_CHECKED;
}
else
{
return BST_UNCHECKED;
}
}
//////////////////////////////////////////////////////////////////////////
void CCustomButton::PreSubclassWindow()
{
LONG lStyle;
lStyle=GetWindowLong(GetSafeHwnd(), GWL_STYLE);
if((lStyle & BS_GROUPBOX) == BS_GROUPBOX)
{
m_bIsGroup=true;
m_ctType=btCustomGroup;
}
else
{
m_bIsGroup=false;
if(((lStyle & BS_GROUPBOX) == BS_CHECKBOX) || ((lStyle & BS_GROUPBOX) == BS_AUTOCHECKBOX))
{
m_ctType=btCustomCheckBox;
}
else
if((lStyle & BS_GROUPBOX) == BS_RADIOBUTTON || ((lStyle & BS_GROUPBOX) == BS_AUTORADIOBUTTON))
{
m_ctType=btCustomRadio;
}
else
{
m_ctType=btCustomButton;
if(lStyle & BS_FLAT)
{
m_bFlat=true;
}
else
{
m_bFlat=false;
}
}
}
GetWindowText(m_strCaption);
m_strActiveCaption=m_strCaption;
ModifyStyle(BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);
//at this stage we do have a HWND and a DC
CDC *pDC;
CRect rc;
GetClientRect(&rc);
pDC=GetDC();
if(pDC != NULL)
{
m_DrawDC.CreateCompatibleDC(pDC);
m_DrawBitmap.CreateCompatibleBitmap(pDC, rc.Width(), rc.Height());
m_hOldDCBmp=m_DrawDC.SelectObject(m_DrawBitmap.GetSafeHandle());
ReleaseDC(pDC);
}
#ifdef _DEBUG
else
{
OutputDebugString(_T("Custom_button failed to get DC."));
}
#endif
CButton::PreSubclassWindow();
}
//////////////////////////////////////////////////////////////////////////
void CCustomButton::OnLButtonUp(UINT nFlags, CPoint point)
{
LONG lStyle;
//if not disabled
lStyle=GetWindowLong(GetSafeHwnd(), GWL_STYLE);
if( !(lStyle & WS_DISABLED))
{
//depending on type...
switch(m_ctType)
{
case btCustomButton:
{
//if regular button, state changes to not pressed
if( !(lStyle & BS_PUSHLIKE))
{
m_bPressed=false;
SetWindowText(m_strCaption);
Invalidate();
}
else
{
//nothing to do
}
break;
}//case Custom button
case btCustomRadio:
{
break;
}//Custom radio
case btCustomCheckBox:
{
break;
}
}
}
CButton::OnLButtonUp(nFlags, point);
}
//////////////////////////////////////////////////////////////////////////
void CCustomButton::OnLButtonDown(UINT nFlags, CPoint point)
{
LONG lStyle;
//if not disabled
lStyle=GetWindowLong(GetSafeHwnd(), GWL_STYLE);
if( !(lStyle & WS_DISABLED))
{
//depending on type...
switch(m_ctType)
{
case btCustomButton:
{
//if regular button, state changes to pressed
if( !(lStyle & BS_PUSHLIKE))
{
m_bPressed=true;
SetWindowText(m_strActiveCaption);
// SetCheck(BST_CHECKED);
}
else
{
//toggle state
m_bPressed= !m_bPressed;
// SetCheck(m_bPressed == true ? BST_CHECKED : BST_UNCHECKED);
SetWindowText(m_bPressed == true ? m_strActiveCaption : m_strCaption);
}
Invalidate();
break;
}//Custom button
case btCustomRadio:
{
//if not checked, check button
if(m_bPressed == false)
{
m_bPressed=true;
SetWindowText(m_strActiveCaption);
SetCheck(BST_CHECKED);
//uncheck all radios in the group
CWnd *pParentWnd;
pParentWnd=GetParent();
if(pParentWnd != NULL)
{
CWnd *pStart, *pSibling;
pStart=pSibling=pParentWnd->GetNextDlgGroupItem(this, TRUE);
do
{
if(pSibling == NULL)
{
break;
}
if(this != pSibling)
// && ((GetWindowLongW( sibling, GWL_STYLE) & 0x0f) == BS_AUTORADIOBUTTON))
{
pSibling->SendMessage(BM_SETCHECK, BST_UNCHECKED, 0);
}
pSibling=pParentWnd->GetNextDlgGroupItem(pSibling, FALSE);
}while(pSibling != pStart);
}//if parent != NULL
}
break;
}
case btCustomCheckBox:
{
//toggle state
m_bPressed= !m_bPressed;
SetWindowText(m_bPressed == true ? m_strActiveCaption : m_strCaption);
SetCheck(m_bPressed == true ? BST_CHECKED : BST_UNCHECKED);
break;
}
}
}
//disable shell animation
//call default handler instead of OnLButtonDown, which would call SHRecognizeGesture
Default();
}
/////////////////////////////////////////////////////////////////////////////
void CCustomButton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
CDC* pDC;
CRect itemRect;
LONG lStyle;
HGDIOBJ hOldFont;
pDC=CDC::FromHandle(lpDIS->hDC);
itemRect=lpDIS->rcItem;
if(m_hCustomFont != NULL)
{
hOldFont=m_DrawDC.SelectObject((HGDIOBJ)m_hCustomFont);
}
lStyle=GetWindowLong(GetSafeHwnd(), GWL_STYLE);
switch(m_ctType)
{
case btCustomButton:
{
DrawPB(&m_DrawDC, &itemRect);
break;
}
case btCustomRadio:
case btCustomCheckBox:
{
DrawRBCB(&m_DrawDC, &itemRect);
break;
}
case btCustomGroup:
{
DrawGB(&m_DrawDC, &itemRect);
break;
}
}
if(m_hCustomFont != NULL)
{
m_DrawDC.SelectObject(hOldFont);
}
//finally blit mem DC to screen
pDC->BitBlt(0, 0, itemRect.Width(), itemRect.Height(), &m_DrawDC, 0, 0, SRCCOPY);
}
//////////////////////////////////////////////////////////////////////////
//gradient background drawing
void CCustomButton::DrawGradient(CDC *pDC)
{
CRect rc;
double dHRStep, dHGStep, dHBStep, dR, dG, dB;
int i, w, h;
GetClientRect(&rc);
w=rc.Width();
h=rc.Height();
//horizontal step values for R, G, B colors
if(m_bPressed == false)
{
dR=GetRValue(m_crHGEnd);
dG=GetGValue(m_crHGEnd);
dB=GetBValue(m_crHGEnd);
}
else
{
dR=GetRValue(m_crHGStart);
dG=GetGValue(m_crHGStart);
dB=GetBValue(m_crHGStart);
}
dHRStep=dR;
dHGStep=dG;
dHBStep=dB;
if(m_bPressed == false)
{
dHRStep-=GetRValue(m_crHGStart);
dHGStep-=GetGValue(m_crHGStart);
dHBStep-=GetBValue(m_crHGStart);
}
else
{
dHRStep-=GetRValue(m_crHGEnd);
dHGStep-=GetGValue(m_crHGEnd);
dHBStep-=GetBValue(m_crHGEnd);
}
dHRStep/=h;
dHGStep/=h;
dHBStep/=h;
//color start values
if(m_bPressed == false)
{
dR=GetRValue(m_crHGStart);
dG=GetGValue(m_crHGStart);
dB=GetBValue(m_crHGStart);
}
else
{
dR=GetRValue(m_crHGEnd);
dG=GetGValue(m_crHGEnd);
dB=GetBValue(m_crHGEnd);
}
//draw horz lines
for(i=2; i<h-2; i++)
{
CPen ptmp(PS_SOLID, 1, RGB(dR, dG, dB));
HGDIOBJ hOldPen=pDC->SelectObject(ptmp);
pDC->MoveTo(2, i);
pDC->LineTo(w-2, i);
pDC->SelectObject(hOldPen);
//next color
dR+=dHRStep;
dG+=dHGStep;
dB+=dHBStep;
}
}
//////////////////////////////////////////////////////////////////////////
//draw group box
void CCustomButton::DrawGB(CDC* pDC, CRect* pRect)
{
CPen framepen;
CBrush framebrush, titlebrush;
HGDIOBJ hOldPen, hOldBrush;
CString str;
LONG lStyle;
UINT nFormat;
bool bIsTxtBottom;
CSize sTextSize;
CRect rcFrame, rcText;
//get style
lStyle=GetWindowLong(GetSafeHwnd(), GWL_STYLE);
//is text bottom?
if((m_cfFlags & bfMask) == bfTextBottom)
{
bIsTxtBottom=true;
}
else
{
bIsTxtBottom=false;
}
//get text dimensions
GetWindowText(str);
sTextSize=pDC->GetTextExtent(str);
if(str == _T(""))
{
//if no title, get current text height with another call
// CSize sTmp;
// sTmp=pDC->GetTextExtent(_T("A"));
// sTextSize.cy=sTmp.cy;
sTextSize.cy=0;
}
//create frame pen
framepen.CreatePen(PS_SOLID, 1, m_crFrame);
framebrush.CreateSolidBrush(m_crBkgIdle);
//create title brush
titlebrush.CreateSolidBrush(m_crFrame);
//draw frame box
hOldPen=pDC->SelectObject(framepen);
hOldBrush=pDC->SelectObject(framebrush);
rcFrame=*pRect;
rcText=rcFrame;
if(bIsTxtBottom == true)
{
rcText.top = rcFrame.bottom - sTextSize.cy;
rcFrame.bottom -= sTextSize.cy/2;
}
else
{
rcText.bottom = rcFrame.top + sTextSize.cy;
rcFrame.top += sTextSize.cy/2;
}
pDC->Rectangle(rcFrame);
pDC->SelectObject(hOldPen);
pDC->SelectObject(hOldBrush);
//draw title rectangle, only if there is caption text
if(str != _T(""))
{
pDC->FillRect(rcText, &titlebrush);
}
//prepare text
GetClientRect(&rcText);
if(str != _T(""))
{
rcText.left += 5;
rcText.right -= 5;
switch(lStyle & BS_CENTER)
{
case BS_CENTER:
{
nFormat=DT_CENTER;
break;
}
case BS_RIGHT:
{
nFormat=DT_RIGHT;
break;
}
default:
nFormat=DT_LEFT;
}
if(bIsTxtBottom == true)
{
nFormat |= DT_BOTTOM;
}
else
{
nFormat |= DT_TOP;
}
pDC->SetTextColor(m_crTxtIdle);
/*
if(m_bTransparent == true)
{
pDC->SetBkMode(TRANSPARENT);
}
else
{
pDC->SetBkMode(OPAQUE);
pDC->SetBkColor(m_crFrame);
}
*/
pDC->SetBkMode(TRANSPARENT);
pDC->DrawText(str, &rcText, nFormat | DT_SINGLELINE);
}
}
//////////////////////////////////////////////////////////////////////////
//draw radio/checkbox
void CCustomButton::DrawRBCB(CDC* pDC, CRect* pRect)
{
COLORREF crColor;
HANDLE hCurrentBmp;
CString strTitle;
CRect rcText, rcBtn, rcImg;
LONG lStyle, lRight;
int tx, ty, ix, iy;
UINT nDTFormat;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -