📄 cnbutton.cpp
字号:
#include "stdafx.h"
#include "CNButton.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CNButton
// Mask for control's type
#define BS_TYPEMASK SS_TYPEMASK
CNButton::CNButton()
{
m_bIsPressed = FALSE;
m_bIsFocused = FALSE;
m_bIsDisabled = FALSE;
m_bMouseOnButton = FALSE;
FreeResources(FALSE);
// Default type is "flat" button
m_bIsFlat = TRUE;
// Button will be tracked also if when the window is inactive (like Internet Explorer)
m_bAlwaysTrack = TRUE; // @@ I change this default value to TRUE!!!
// By default draw border in "flat" button
m_bDrawBorder = TRUE;
// By default icon is aligned horizontally
m_byAlign = ST_ALIGN_HORIZ;
// By default, for "flat" button, don't draw the focus rect
m_bDrawFlatFocus = FALSE;
// By default the button is not the default button
m_bIsDefault = FALSE;
// Invalid value, since type still unknown
m_nTypeStyle = BS_TYPEMASK;
// By default the button is not a checkbox
m_bIsCheckBox = FALSE;
m_nCheck = 0;
// Set default colors
SetDefaultColors(FALSE);
// No tooltip created
m_ToolTip.m_hWnd = NULL;
// Do not draw as a transparent button
m_bDrawTransparent = FALSE;
m_pbmpOldBk = NULL;
// No URL defined
SetURL(NULL);
// No cursor defined
m_hCursor = NULL;
// No associated menu
m_hMenu = NULL;
m_hParentWndMenu = NULL;
m_bMenuDisplayed = FALSE;
} // End of CNButton
CNButton::~CNButton()
{
// Restore old bitmap (if any)
if (m_dcBk.m_hDC && m_pbmpOldBk)
{
m_dcBk.SelectObject(m_pbmpOldBk);
} // if
FreeResources();
// Destroy the cursor (if any)
if (m_hCursor) ::DestroyCursor(m_hCursor);
// Destroy the menu (if any)
if (m_hMenu) ::DestroyMenu(m_hMenu);
} // End of ~CNButton
BEGIN_MESSAGE_MAP(CNButton, CButton)
//{{AFX_MSG_MAP(CNButton)
ON_WM_SETCURSOR()
ON_WM_KILLFOCUS()
ON_WM_MOUSEMOVE()
ON_WM_SYSCOLORCHANGE()
ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked)
ON_WM_ACTIVATE()
ON_WM_ENABLE()
ON_WM_CANCELMODE()
ON_WM_GETDLGCODE()
ON_WM_CTLCOLOR_REFLECT()
//}}AFX_MSG_MAP
ON_MESSAGE(BM_SETSTYLE, OnSetStyle)
ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
END_MESSAGE_MAP()
void CNButton::FreeResources(BOOL bCheckForNULL)
{
if (bCheckForNULL)
{
// Destroy icons
// Note: the following two lines MUST be here! even if
// BoundChecker says they are unnecessary!
// @@
//if (m_csIcons[0].hIcon) ::DestroyIcon(m_csIcons[0].hIcon);
//if (m_csIcons[1].hIcon) ::DestroyIcon(m_csIcons[1].hIcon);
// Destroy bitmaps
if (m_csBitmaps[0].hBitmap) ::DeleteObject(m_csBitmaps[0].hBitmap);
if (m_csBitmaps[1].hBitmap) ::DeleteObject(m_csBitmaps[1].hBitmap);
// Destroy mask bitmaps
if (m_csBitmaps[0].hMask) ::DeleteObject(m_csBitmaps[0].hMask);
if (m_csBitmaps[1].hMask) ::DeleteObject(m_csBitmaps[1].hMask);
} // if
::ZeroMemory(&m_csIcons, sizeof(m_csIcons));
::ZeroMemory(&m_csBitmaps, sizeof(m_csBitmaps));
} // End of FreeResources
void CNButton::PreSubclassWindow()
{
UINT nBS;
nBS = GetButtonStyle();
// Set initial control type
m_nTypeStyle = nBS & BS_TYPEMASK;
// Check if this is a checkbox
if (nBS & BS_CHECKBOX) m_bIsCheckBox = TRUE;
// Set initial default state flag
if (m_nTypeStyle == BS_DEFPUSHBUTTON)
{
// Set default state for a default button
m_bIsDefault = TRUE;
// Adjust style for default button
m_nTypeStyle = BS_PUSHBUTTON;
} // If
// You should not set the Owner Draw before this call
// (don't use the resource editor "Owner Draw" or
// ModifyStyle(0, BS_OWNERDRAW) before calling PreSubclassWindow() )
ASSERT(m_nTypeStyle != BS_OWNERDRAW);
// Switch to owner-draw
ModifyStyle(BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);
CButton::PreSubclassWindow();
} // End of PreSubclassWindow
UINT CNButton::OnGetDlgCode()
{
UINT nCode = CButton::OnGetDlgCode();
// Tell the system if we want default state handling
// (losing default state always allowed)
nCode |= (m_bIsDefault ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON);
return nCode;
} // End of OnGetDlgCode
BOOL CNButton::PreTranslateMessage(MSG* pMsg)
{
InitToolTip();
m_ToolTip.RelayEvent(pMsg);
return CButton::PreTranslateMessage(pMsg);
} // End of PreTranslateMessage
LRESULT CNButton::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch( message)
{
case WM_LBUTTONDBLCLK:
message = WM_LBUTTONDOWN;
break;
default:
break;
}
return CButton::DefWindowProc(message, wParam, lParam);
} // End of DefWindowProc
HBRUSH CNButton::CtlColor(CDC* pDC, UINT nCtlColor)
{
return (HBRUSH)::GetStockObject(NULL_BRUSH);
} // End of CtlColor
void CNButton::OnSysColorChange()
{
CButton::OnSysColorChange();
m_dcBk.DeleteDC();
m_bmpBk.DeleteObject();
} // End of OnSysColorChange
LRESULT CNButton::OnSetStyle(WPARAM wParam, LPARAM lParam)
{
UINT nNewType = (wParam & BS_TYPEMASK);
// Update default state flag
if (nNewType == BS_DEFPUSHBUTTON)
{
m_bIsDefault = TRUE;
} // if
else if (nNewType == BS_PUSHBUTTON)
{
// Losing default state always allowed
m_bIsDefault = FALSE;
} // if
// Can't change control type after owner-draw is set.
// Let the system process changes to other style bits
// and redrawing, while keeping owner-draw style
return DefWindowProc(BM_SETSTYLE,
(wParam & ~BS_TYPEMASK) | BS_OWNERDRAW, lParam);
} // End of OnSetStyle
void CNButton::OnEnable(BOOL bEnable)
{
CButton::OnEnable(bEnable);
if (bEnable == FALSE)
{
CWnd* pWnd = GetParent()->GetNextDlgTabItem(this);
if (pWnd)
pWnd->SetFocus();
else
GetParent()->SetFocus();
CancelHover();
} // if
} // End of OnEnable
void CNButton::OnKillFocus(CWnd * pNewWnd)
{
CButton::OnKillFocus(pNewWnd);
CancelHover();
} // End of OnKillFocus
void CNButton::OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized)
{
CButton::OnActivate(nState, pWndOther, bMinimized);
if (nState == WA_INACTIVE) CancelHover();
} // End of OnActivate
void CNButton::OnCancelMode()
{
CButton::OnCancelMode();
CancelHover();
} // End of OnCancelMode
BOOL CNButton::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// If a cursor was specified then use it!
if (m_hCursor != NULL)
{
::SetCursor(m_hCursor);
return TRUE;
} // if
return CButton::OnSetCursor(pWnd, nHitTest, message);
} // End of OnSetCursor
void CNButton::CancelHover()
{
// Only for flat buttons
if (m_bIsFlat)
{
if (m_bMouseOnButton)
{
m_bMouseOnButton = FALSE;
Invalidate();
} // if
} // if
} // End of CancelHover
void CNButton::OnMouseMove(UINT nFlags, CPoint point)
{
CWnd* wndUnderMouse = NULL;
CWnd* wndActive = this;
TRACKMOUSEEVENT csTME;
CButton::OnMouseMove(nFlags, point);
ClientToScreen(&point);
wndUnderMouse = WindowFromPoint(point);
// If the mouse enter the button with the left button pressed then do nothing
if (nFlags & MK_LBUTTON && m_bMouseOnButton == FALSE) return;
// If our button is not flat then do nothing
if (m_bIsFlat == FALSE) return;
if (m_bAlwaysTrack == FALSE) wndActive = GetActiveWindow();
if (wndUnderMouse && wndUnderMouse->m_hWnd == m_hWnd && wndActive)
{
if (!m_bMouseOnButton)
{
m_bMouseOnButton = TRUE;
Invalidate();
csTME.cbSize = sizeof(csTME);
csTME.dwFlags = TME_LEAVE;
csTME.hwndTrack = m_hWnd;
::_TrackMouseEvent(&csTME);
} // if
} else CancelHover();
} // End of OnMouseMove
// Handler for WM_MOUSELEAVE
LRESULT CNButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
CancelHover();
return 0;
} // End of OnMouseLeave
BOOL CNButton::OnClicked()
{
if (m_bIsCheckBox)
{
m_nCheck = !m_nCheck;
Invalidate();
} // if
else
{
// Handle the menu (if any)
if (m_hMenu)
{
HMENU hSubMenu = NULL;
CRect rWnd;
hSubMenu = ::GetSubMenu(m_hMenu, 0);
GetWindowRect(rWnd);
m_bMenuDisplayed = TRUE;
Invalidate();
::TrackPopupMenuEx(hSubMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON, rWnd.left, rWnd.bottom, m_hParentWndMenu, NULL);
m_bMenuDisplayed = FALSE;
Invalidate();
} // if
else
{
// Handle the URL (if any)
if (_tcslen(m_szURL) > 0)
{
SHELLEXECUTEINFO csSEI;
memset(&csSEI, 0, sizeof(csSEI));
csSEI.cbSize = sizeof(SHELLEXECUTEINFO);
csSEI.fMask = SEE_MASK_FLAG_NO_UI;
csSEI.lpVerb = _T("open");
csSEI.lpFile = m_szURL;
csSEI.nShow = SW_SHOWMAXIMIZED;
::ShellExecuteEx(&csSEI);
} // if
} // else
} // else
return FALSE;
} // End of OnClicked
void CNButton::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
CDC* pDC = CDC::FromHandle(lpDIS->hDC);
CPen* pOldPen;
// Checkbox?
if (m_bIsCheckBox)
{
m_bIsPressed = (lpDIS->itemState & ODS_SELECTED) || (m_nCheck != 0);
} // if
else // Normal button OR other button style ...
{
m_bIsPressed = (lpDIS->itemState & ODS_SELECTED);
// If there is a menu and it's displayed, draw the button as pressed
if (m_hMenu && m_bMenuDisplayed) m_bIsPressed = TRUE;
} // else
m_bIsFocused = (lpDIS->itemState & ODS_FOCUS);
m_bIsDisabled = (lpDIS->itemState & ODS_DISABLED);
CRect itemRect = lpDIS->rcItem;
pDC->SetBkMode(TRANSPARENT);
if (m_bIsFlat == FALSE)
{
if (m_bIsFocused || m_bIsDefault)
{
CBrush br(RGB(0,0,0));
pDC->FrameRect(&itemRect, &br);
// itemRect.DeflateRect(1, 1); // @@
} // if
} // if
// Prepare draw... paint button background
// Draw transparent?
if (m_bDrawTransparent)
PaintBk(pDC);
else
OnDrawBackground(pDC, &itemRect);
// Draw pressed button
if (m_bIsPressed)
{
if (m_bIsFlat)
{
if (m_bDrawBorder)
OnDrawBorder(pDC, &itemRect);
}
else
{
CBrush brBtnShadow(GetSysColor(COLOR_BTNSHADOW));
pDC->FrameRect(&itemRect, &brBtnShadow);
}
}
else // ...else draw non pressed button
{
CPen penBtnHiLight(PS_SOLID, 0, GetSysColor(COLOR_BTNHILIGHT)); // White
CPen pen3DLight(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT)); // Light gray
CPen penBtnShadow(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW)); // Dark gray
CPen pen3DDKShadow(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW)); // Black
if (m_bIsFlat)
{
if (m_bMouseOnButton && m_bDrawBorder)
OnDrawBorder(pDC, &itemRect);
}
else
{
// Draw top-left borders
// White line
pOldPen = pDC->SelectObject(&penBtnHiLight);
pDC->MoveTo(itemRect.left, itemRect.bottom-1);
pDC->LineTo(itemRect.left, itemRect.top);
pDC->LineTo(itemRect.right, itemRect.top);
// Light gray line
pDC->SelectObject(pen3DLight);
pDC->MoveTo(itemRect.left+1, itemRect.bottom-1);
pDC->LineTo(itemRect.left+1, itemRect.top+1);
pDC->LineTo(itemRect.right, itemRect.top+1);
// Draw bottom-right borders
// Black line
pDC->SelectObject(pen3DDKShadow);
pDC->MoveTo(itemRect.left, itemRect.bottom-1);
pDC->LineTo(itemRect.right-1, itemRect.bottom-1);
pDC->LineTo(itemRect.right-1, itemRect.top-1);
// Dark gray line
pDC->SelectObject(penBtnShadow);
pDC->MoveTo(itemRect.left+1, itemRect.bottom-2);
pDC->LineTo(itemRect.right-2, itemRect.bottom-2);
pDC->LineTo(itemRect.right-2, itemRect.top);
//
pDC->SelectObject(pOldPen);
} // else
} // else
// Read the button's title
CString sTitle;
GetWindowText(sTitle);
DWORD Format = DT_VCENTER | DT_LEFT |DT_SINGLELINE ;
CFont font;
CFont *OldFont;
VERIFY(font.CreateFont(
12, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
FALSE, // cStrikeOut
DEFAULT_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("宋体"))); // lpszFacename
OldFont = pDC->SelectObject(&font);
CRect captionRect = lpDIS->rcItem;
// Draw the icon
if (m_csIcons[0].hIcon)
{
DrawTheIcon(pDC, !sTitle.IsEmpty(), &lpDIS->rcItem, &captionRect, m_bIsPressed, m_bIsDisabled);
} // if
if (m_csBitmaps[0].hBitmap)
{
pDC->SetBkColor(RGB(255,255,255));
DrawTheBitmap(pDC, !sTitle.IsEmpty(), &lpDIS->rcItem, &captionRect, m_bIsPressed, m_bIsDisabled);
captionRect.OffsetRect(4,0);
}
else
{
captionRect.OffsetRect(22,0);
}
// Write the button title (if any)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -