📄 unibutton.cpp
字号:
// UniButton.cpp : implementation file
//
#include "stdafx.h"
#include "UniButton.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CUniButton
CUniButton::CUniButton()
{
m_pNormal = NULL;
m_pSelected = NULL;
m_pHover = NULL;
m_pDisabled = NULL;
m_hRgn = 0;
m_bHover = FALSE;
m_bCapture = FALSE;
m_bMouseDown = FALSE;
m_bHilighted = FALSE;
}
CUniButton::~CUniButton()
{
delete m_pNormal;
delete m_pSelected;
delete m_pHover;
delete m_pDisabled;
DeleteObject(m_hRgn);
}
BEGIN_MESSAGE_MAP(CUniButton, CButton)
//{{AFX_MSG_MAP(CUniButton)
ON_WM_ERASEBKGND()
ON_WM_MOUSEMOVE()
ON_WM_CREATE()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CUniButton message handlers
void CUniButton::PreSubclassWindow()
{
// change window style to allow owner draw
ModifyStyle(0, BS_OWNERDRAW | BS_PUSHBUTTON);
CButton::PreSubclassWindow();
}
int CUniButton::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CButton::OnCreate(lpCreateStruct) == -1)
return -1;
// assign new region to a window
SetWindowRgn(m_hRgn, true);
return 0;
}
void CUniButton::OnLButtonDown(UINT nFlags, CPoint point)
{
// record that mouse is down
m_bMouseDown = TRUE;
if (!m_bCapture) {
SetCapture();
m_bCapture = true;
}
CButton::OnLButtonDown(nFlags, point);
}
void CUniButton::OnLButtonUp(UINT nFlags, CPoint point)
{
// record that mouse is released
CButton::OnLButtonUp(nFlags, point);
m_bMouseDown = FALSE;
if (m_bCapture) {
ReleaseCapture();
m_bCapture = false;
}
CheckHover(point);
}
void CUniButton::OnMouseMove(UINT nFlags, CPoint point)
{
// Test if mouse is above the button.
if (!m_bMouseDown)
CheckHover(point);
CButton::OnMouseMove(nFlags, point);
}
void CUniButton::CheckHover(CPoint point)
{
if (HitTest(point)) {
if (!m_bCapture) {
SetCapture();
m_bCapture = true;
}
if (!m_bHover) {
m_bHover = TRUE;
RedrawWindow();
}
}
else {
if (m_bCapture) {
ReleaseCapture();
m_bCapture = false;
}
m_bHover = FALSE;
RedrawWindow();
}
}
LRESULT CUniButton::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// I have noticed that default windows buttons can be clicked very quickly.
// Double or single click both result in a button being pushed down.
// For owner drawn buttons this is not the case. Double click does
// not push button down. Here is a solution for the problem:
// double click message is substituted for single click.
if (message == WM_LBUTTONDBLCLK) {
message = WM_LBUTTONDOWN;
}
return CButton::DefWindowProc(message, wParam, lParam);
}
BOOL CUniButton::HitTest(CPoint point)
{
BOOL result = FALSE;
// Obtain handle to window region.
HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
GetWindowRgn(hRgn);
CRect rgnRect;
GetRgnBox(hRgn, &rgnRect);
// First check if point is in region bounding rect.
// Then check if point is in the region in adition to being in the bouding rect.
result = PtInRect(&rgnRect, point) && PtInRegion(hRgn, point.x, point.y);
// Clean up and exit.
DeleteObject(hRgn);
return result;
}
BOOL CUniButton::OnEraseBkgnd(CDC* pDC)
{
// do not erase background
return 1;
}
//////////////////////// DRAWING ROUTINES ////////////////////////////
void CUniButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// prepare DC
CDC* pDC = CDC::FromHandle(lpDrawItemStruct -> hDC);
CRect rect;
GetClientRect(rect);
// draw button to the screen
DrawButton(pDC, &rect, lpDrawItemStruct -> itemState);
}
void CUniButton::DrawButton(CDC * pDC, CRect * pRect, UINT state)
{
// create memory DC
CDC * pMemDC = new CDC;
pMemDC -> CreateCompatibleDC(pDC);
CBitmap * pOldBitmap;
// get region
HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
GetWindowRgn(hRgn);
// select bitmap to paint depending upon button state
if ( m_bHilighted ) {
pOldBitmap = pMemDC -> SelectObject(m_pSelected);
}
else if (state & ODS_DISABLED) {
pOldBitmap = pMemDC -> SelectObject(m_pDisabled);
}
else {
if (state & ODS_SELECTED) {
pOldBitmap = pMemDC -> SelectObject(m_pSelected);
}
else {
if (m_bHover) {
pOldBitmap = pMemDC -> SelectObject(m_pHover);
}
else {
pOldBitmap = pMemDC -> SelectObject(m_pNormal);
}
}
}
// paint using region for clipping
::SelectClipRgn(pDC -> GetSafeHdc(), hRgn);
pDC -> BitBlt(0, 0, pRect -> Width(), pRect -> Height(), pMemDC, 0, 0, SRCCOPY);
::SelectClipRgn(pDC -> GetSafeHdc(), NULL);
// clean up
DeleteObject(hRgn);
pMemDC -> SelectObject(pOldBitmap);
delete pMemDC;
}
BOOL CUniButton::Create( LPCTSTR lpszCaption,
DWORD dwStyle,
const CPoint point,
const HRGN hRgn,
CWnd * pParentWnd,
UINT nID, // Button Resource ID
UINT nIDBkNormal, // Button background bitmap resource ID(Normal Status)
UINT nIDBkPush, // Button background bitmap resource ID(Selected Status)
UINT nIDBkHover, // Button background bitmap resource ID(Hover Status)
UINT nIDBkDisable) // Button background bitmap resource ID(Disabled Status)
{
// store region in member variable
DeleteObject(m_hRgn);
m_hRgn = CreateRectRgn(0, 0, 31, 31);
CRect box(0, 0, 0, 0);
if (m_hRgn != 0)
CombineRgn(m_hRgn, hRgn, 0, RGN_COPY);
// make sure that region bounding rect is located in (0, 0)
GetRgnBox(m_hRgn, &box);
OffsetRgn(m_hRgn, -box.left, -box.top);
GetRgnBox(m_hRgn, &box);
// update position of region center for caption output
m_CenterPoint = CPoint(box.left + box.Width() /2 , box.top + box.Height() /2);
box.OffsetRect(point);
m_pNormal = new CBitmap;
m_pNormal->LoadBitmap( nIDBkNormal );
m_pSelected = new CBitmap;
m_pSelected->LoadBitmap( nIDBkPush );
m_pHover = new CBitmap;
m_pHover->LoadBitmap( nIDBkHover );
m_pDisabled = new CBitmap;
m_pDisabled->LoadBitmap( nIDBkDisable );
return CButton::Create(lpszCaption, dwStyle, box, pParentWnd, nID);
}
void CUniButton::SetState(BOOL bHighlight)
{
m_bHilighted = bHighlight;
RedrawWindow();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -