📄 spinbuttonctrlex.cpp
字号:
// LBSpinButtonCtrl.cpp : implementation file
//
// Copyright ?1999 Oleg Lobach, All Rights Reserved.
//
// mailto:oleglb@mail.ru
//or
// mailto:oleg@alexen.ru
//
//
// This source file may be redistributed unmodified by any means PROVIDING
// it is NOT sold for profit without the authors expressed written
// consent, and providing that this notice and the authors name and all
// copyright notices remain intact. This software is by no means to be
// included as part of any third party components library, or as part any
// development solution that offers MFC extensions that are sold for profit.
//
// If the source code is used in any commercial applications then a statement
// along the lines of:
//
// "Portions Copyright ?1999 Oleg Lobach" must be included in the "Startup
// Banner", "About Box" or "Printed Documentation". This software is provided
// "as is" without express or implied warranty. Use it at your own risk! The
// author(s) accepts no liability for any damage/loss of business that this
// product may cause.
//
/////////////////////////////////////////////////////////////////////////////
//****************************************************************************
#include "stdafx.h"
#include "SpinButtonCtrlEx.h"
#pragma warning(disable:4786)
#include <map>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
using namespace std;
namespace techwin
{
#ifdef _WIN32_WCE
CSpinButtonCtrlEx::CSpinButtonCtrlEx()
{
}
CSpinButtonCtrlEx::~CSpinButtonCtrlEx()
{
}
#else
typedef map <HWND,HWND> HWNDMAP;
static HWNDMAP gHandleMap;
static LRESULT CALLBACK FilterBuddyMsgProc(int code,WPARAM wParam, LPARAM lParam );
static HHOOK ghHook=NULL;
/////////////////////////////////////////////////////////////////////////////
// CSpinButtonCtrlEx
CSpinButtonCtrlEx::CSpinButtonCtrlEx():m_hWndBuddy(NULL),
m_bVertical(true),m_nSpinAlign(Outside),
m_bDefaultDirection(true),m_bBuddyIsEdit(false),
m_rctIsPressed(0,0,0,0),m_bActiveSpinPressed(false),
m_bAutoDisable(true)
{
}
CSpinButtonCtrlEx::~CSpinButtonCtrlEx()
{
}
BEGIN_MESSAGE_MAP(CSpinButtonCtrlEx, CSpinButtonCtrl)
//{{AFX_MSG_MAP(CSpinButtonCtrlEx)
ON_NOTIFY_REFLECT_EX(UDN_DELTAPOS, OnDeltapos)
ON_WM_LBUTTONDOWN()
ON_WM_ERASEBKGND()
ON_WM_LBUTTONUP()
ON_WM_DESTROY()
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSpinButtonCtrlEx message handlers
void CSpinButtonCtrlEx::PreSubclassWindow()
{
//I need custom pens to draw up_down control
COLORREF clr=::GetSysColor(COLOR_3DDKSHADOW);
m_penDarkShadow=::CreatePen(PS_SOLID,0,clr);
clr=::GetSysColor(COLOR_BTNSHADOW);
m_penShadow=::CreatePen(PS_SOLID,0,clr);
clr=::GetSysColor(COLOR_3DHILIGHT);
m_penLight=::CreatePen(PS_SOLID,0,clr);
clr=::GetSysColor(COLOR_3DLIGHT);
m_penLightShadow=::CreatePen(PS_SOLID,0,clr);
clr=::GetSysColor(COLOR_BTNFACE);
m_penButtonFace=::CreatePen(PS_SOLID,0,clr);
Init();
CSpinButtonCtrl::PreSubclassWindow();
}
void CSpinButtonCtrlEx::OnPaint()
{
if(m_bAutoDisable)
{
//Draw control by hands
CPaintDC RealDC(this); // device context
CRect rctPaint=m_rctClient;
CRect rcPaintUp,rcPaintDown;
//To get rid of flickering we are drawing to memory DC (dc),
//and then BitBlting it to the screen.
//So we have to create compatible memory DC and select bitmap into it.
CDC dc;
CBitmap bmpMem,*pOldMemBmp;
dc.CreateCompatibleDC(&RealDC);
bmpMem.CreateCompatibleBitmap(&RealDC,rctPaint.Width(),rctPaint.Height());
pOldMemBmp=dc.SelectObject(&bmpMem);
//As so I bypassed WM_ERASEBCKGND, do it here
dc.FillSolidRect(&rctPaint,::GetSysColor(COLOR_BTNFACE));
if(::IsWindow(m_hWndBuddy) && m_nSpinAlign!=Outside )
{
rctPaint.top+=2;
rctPaint.bottom-=2;
if(m_nSpinAlign == OnRightInside)
rctPaint.right-=2;
else
rctPaint.left+=2;
}
rcPaintUp= rctPaint;
//Draw control, depending on it alignment and orientation
if(m_bVertical)
{
rcPaintUp.bottom=rcPaintUp.top+rcPaintUp.Height()/2;
rcPaintDown=rctPaint;
rcPaintDown.top=rcPaintDown.bottom-rcPaintUp.Height();
dc.DrawFrameControl(&rcPaintUp,DFC_SCROLL,DFCS_SCROLLUP);
dc.DrawFrameControl(&rcPaintDown,DFC_SCROLL,DFCS_SCROLLDOWN);
}
else
{
rcPaintUp.right=rcPaintUp.left+rcPaintUp.Width()/2;
rcPaintDown=rctPaint;
rcPaintDown.left=rcPaintDown.right-rcPaintUp.Width();
dc.DrawFrameControl(&rcPaintUp,DFC_SCROLL,DFCS_SCROLLLEFT);
dc.DrawFrameControl(&rcPaintDown,DFC_SCROLL,DFCS_SCROLLRIGHT);
}
if(::IsWindow(m_hWndBuddy) && m_nSpinAlign!=Outside )
{
//We are inside buddy,so have to draw buddy's border around
//CSpinButtonCtrlEx
//We use m_rctClient as so rctPaint may have been already modified.
if(m_nSpinAlign == OnRightInside)
{
::SelectObject(dc.m_hDC,m_penShadow);
dc.MoveTo(m_rctClient.left,m_rctClient.top);
dc.LineTo(m_rctClient.right,m_rctClient.top);
::SelectObject(dc.m_hDC,m_penDarkShadow);
dc.MoveTo(m_rctClient.left,m_rctClient.top+1);
dc.LineTo(m_rctClient.right-1,m_rctClient.top+1);
::SelectObject(dc.m_hDC,m_penLight);
dc.LineTo(m_rctClient.right-1,m_rctClient.bottom-1);
dc.LineTo(m_rctClient.left-1,m_rctClient.bottom-1);
}
else
{
::SelectObject(dc.m_hDC,m_penShadow);
dc.MoveTo(m_rctClient.right,m_rctClient.top);
dc.LineTo(m_rctClient.left,m_rctClient.top);
dc.LineTo(m_rctClient.left,m_rctClient.bottom);
::SelectObject(dc.m_hDC,m_penDarkShadow);
dc.MoveTo(m_rctClient.right,m_rctClient.top+1);
dc.LineTo(m_rctClient.left+1,m_rctClient.top+1);
dc.LineTo(m_rctClient.left+1,m_rctClient.top+1);
dc.LineTo(m_rctClient.left+1,m_rctClient.bottom-1);
::SelectObject(dc.m_hDC,m_penLight);
dc.LineTo(m_rctClient.right+1,m_rctClient.bottom-1);
}
}
//If the position reached the limit, draw corresponding
//part of control as disabled
switch (m_nSpinState)
{
case DisableRight:
if(m_bDefaultDirection)
{
if(m_bVertical)
DisableRect(dc,rcPaintDown);
else
DisableRect(dc,rcPaintUp);
}
else
{
if(m_bVertical)
DisableRect(dc,rcPaintUp);
else
DisableRect(dc,rcPaintDown);
}
break;
case DisableLeft:
if(m_bDefaultDirection)
{
if(m_bVertical)
DisableRect(dc,rcPaintUp);
else
DisableRect(dc,rcPaintDown);
}
else
{
if(m_bVertical)
DisableRect(dc,rcPaintDown);
else
DisableRect(dc,rcPaintUp);
}
break;
}
if(m_bActiveSpinPressed)
{
//The control's position has changed, so we have to
//draw corresponding part as pressed
if(m_rctIsPressed.IsRectEmpty())
{
CPoint pt=::GetMessagePos();
ScreenToClient(&pt);
if(rcPaintUp.PtInRect(pt))
{
m_rctIsPressed = rcPaintUp;
}
else
{
if(rcPaintDown.PtInRect(pt))
{
m_rctIsPressed = rcPaintDown;
}
}
}
DrawPressedRect(dc,m_rctIsPressed);
m_bActiveSpinPressed=false;
}
//Copy drawing from memory device context to the screen
RealDC.BitBlt(m_rctClient.left,m_rctClient.top,m_rctClient.Width(),
m_rctClient.Height(),&dc,m_rctClient.left,m_rctClient.top,SRCCOPY);
dc.SelectObject(pOldMemBmp);
}
else
{
//Let the Windows do it's work
Default();
return;
}
}
void CSpinButtonCtrlEx::DisableRect(CDC &dc, const CRect &rectDisable) const
{
CBitmap bmpMask,*pBmpBeforeMask;
CBrush brushMask,*pOldBrush;
COLORREF clrOldBack,clrOldText;
CDC memDC;
memDC.CreateCompatibleDC(&dc);
CRect rctClient;
CRect rectToDisable=rectDisable;
GetClientRect(&rctClient);
//Create MONO bitmap
bmpMask.CreateBitmap(rctClient.Width(),rctClient.Height(),1,1,NULL);
pBmpBeforeMask=memDC.SelectObject(&bmpMask);
CDC dcSrc;
dcSrc.CreateCompatibleDC(&dc);
CBitmap bmpSrc,*pBmpBeforeSrc;
bmpSrc.CreateCompatibleBitmap(&dc,rctClient.Width(),rctClient.Height());
pBmpBeforeSrc=dcSrc.SelectObject(&bmpSrc);
clrOldBack=dc.SetBkColor(RGB(0,0,0)); //Suppose arrows are black
//Create mask into memDC (the pixels which in dc were black - become white in memDC,
//all others pixels in memDC become black)
memDC.BitBlt(rectToDisable.left,rectToDisable.top,
rectToDisable.Width(),rectToDisable.Height(),&dc,
rectToDisable.left,rectToDisable.top,SRCCOPY);
//Copy bitmap from screen to memory DC
dcSrc.BitBlt(rectToDisable.left,rectToDisable.top,
rectToDisable.Width(),rectToDisable.Height(),&dc,
rectToDisable.left,rectToDisable.top,SRCCOPY);
CBrush brushSrc;
rectToDisable.DeflateRect(1,1);
//Apply DSPxax ROP code to memory dc . As result black arrow become
// of COLOR_3DSHADOW
brushSrc.CreateSolidBrush(::GetSysColor(COLOR_3DSHADOW));
dcSrc.SelectObject(&brushSrc);
dcSrc.SetBkColor(RGB(255,255,255));
dcSrc.SetTextColor(RGB(0,0,0));
dcSrc.BitBlt(rectToDisable.left,rectToDisable.top,
rectToDisable.Width(),rectToDisable.Height(),&memDC,
rectToDisable.left,rectToDisable.top,0x00E20746L);
//Apply DSPxax ROP code to screen dc and shift result one pixel left and bottom.
//As result black arrow become shifted and of COLOR_3DLIGHT.
brushMask.CreateSolidBrush(::GetSysColor(COLOR_3DHILIGHT));
pOldBrush = dc.SelectObject(&brushMask);
dc.SetBkColor(RGB(255,255,255));
clrOldText=dc.SetTextColor(RGB(0,0,0));
dc.BitBlt(rectToDisable.left+1,rectToDisable.top+1,
rectToDisable.Width()-1,rectToDisable.Height()-1,&memDC,
rectToDisable.left,rectToDisable.top,0x00E20746L);
// Draw memory dc (dcSrc) transparently over device dc.
//As result only arrow of color COLOR_3DSHADOW will be drawn over device dc
//-------------------------------------------------------------------------
//Create mask into memDC (the pixels which in dc were COLOR_BTNFACE
//- become white in memDC,all others pixels in memDC become black)
dcSrc.SetBkColor(GetSysColor(COLOR_BTNFACE));
memDC.BitBlt(rectToDisable.left,rectToDisable.top,
rectToDisable.Width(),rectToDisable.Height(),&dcSrc,
rectToDisable.left,rectToDisable.top,SRCCOPY);
dc.BitBlt(rectToDisable.left,rectToDisable.top,
rectToDisable.Width(),rectToDisable.Height(),&dcSrc,
rectToDisable.left,rectToDisable.top,SRCINVERT);
dc.BitBlt(rectToDisable.left,rectToDisable.top,
rectToDisable.Width(),rectToDisable.Height(),&memDC,
rectToDisable.left,rectToDisable.top,SRCAND);
dc.BitBlt(rectToDisable.left,rectToDisable.top,
rectToDisable.Width(),rectToDisable.Height(),&dcSrc,
rectToDisable.left,rectToDisable.top,SRCINVERT);
//-------------------------------------------------------------------------
//Restore resourses
memDC.SelectObject(pBmpBeforeMask);
dcSrc.SelectObject(pBmpBeforeSrc);
dc.SetBkColor(clrOldBack);
dc.SetTextColor(clrOldText);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -