📄 spinbuttonctrlex.cpp
字号:
dc.SelectObject(pOldBrush);
}
void CSpinButtonCtrlEx::DrawPressedRect(CDC &dc, const CRect &rctToDown) const
{
CRect rctDown=rctToDown;
HPEN hOldPen;
//Offset bitmap one pixel left and down
dc.BitBlt(rctDown.left+1,rctDown.top+1,
rctDown.Width()-1,rctDown.Height()-1,&dc,
rctDown.left,rctDown.top,SRCCOPY);
// Draw the border of pressed button
rctDown.bottom-=1;
hOldPen = (HPEN)SelectObject(dc.m_hDC,m_penShadow);
dc.MoveTo(rctDown.left,rctDown.bottom-1);
dc.LineTo(rctDown.left,rctDown.top);
dc.LineTo(rctDown.right-1,rctDown.top);
SelectObject(dc.m_hDC,m_penLight);
dc.LineTo(rctDown.right-1,rctDown.bottom);
dc.LineTo(rctDown.left-1,rctDown.bottom);
SelectObject(dc.m_hDC,m_penDarkShadow);
dc.MoveTo(rctDown.left+1,rctDown.bottom-2);
dc.LineTo(rctDown.left+1,rctDown.top+1);
dc.LineTo(rctDown.right-2,rctDown.top+1);
SelectObject(dc.m_hDC,m_penLightShadow);
dc.LineTo(rctDown.right-2,rctDown.bottom-1);
dc.LineTo(rctDown.left,rctDown.bottom-1);
SelectObject(dc.m_hDC,m_penButtonFace);
dc.MoveTo(rctDown.left+2,rctDown.bottom-2);
dc.LineTo(rctDown.left+2,rctDown.top+2);
dc.LineTo(rctDown.right-2,rctDown.top+2);
SelectObject(dc.m_hDC,hOldPen);
}
void CSpinButtonCtrlEx::Init()
{
//We need to know m_hWndBuddy even if UDS_WRAP style applied, to fix bug
// with possible incorrect Z-order of buddy/spin
m_hWndBuddy=(HWND)::SendMessage(m_hWnd, UDM_GETBUDDY, 0, 0l);
DWORD dwStyle=::GetWindowLong(m_hWnd,GWL_STYLE);
if(dwStyle & UDS_WRAP)
m_bAutoDisable=false; //if the UDS_WRAP style was applied, we can't disable arrows
// The m_bAutoDisable can also be set from outside using SetAutoDisable method;
if(m_bAutoDisable)
{
//Determine the orientation and alignment of this CSpinButtonCtrlEx
if(dwStyle & UDS_ALIGNRIGHT )
m_nSpinAlign=OnRightInside;
else
{
if(dwStyle & UDS_ALIGNLEFT)
{
m_nSpinAlign=OnLeftInside;
}
}
if(dwStyle & UDS_HORZ)
m_bVertical=false;
//Determine the control's limits and direction of increasing of it's position
GetRange32(m_nMinPos,m_nMaxPos);
if( m_nMinPos < m_nMaxPos)
m_bDefaultDirection =false;
else
{
int nTemp = m_nMinPos;
m_nMinPos = m_nMaxPos;
m_nMaxPos=nTemp;
}
GetClientRect(&m_rctClient);
m_nPrevPos = GetPos();
//Determine the control's initial enable/disable state
m_nSpinState = BothEnable;
if(m_nPrevPos == m_nMinPos)
m_nSpinState = DisableLeft;
else
{
if(m_nPrevPos == m_nMaxPos)
m_nSpinState = DisableRight;
}
if(::IsWindow(m_hWndBuddy))
{
TCHAR buf[5];
::GetClassName(m_hWndBuddy,buf,sizeof(buf)/sizeof(buf[0]));
if(!_tcscmp(buf,_T("Edit")))
{
//The class of buddy is Edit
m_bBuddyIsEdit=true;
//I need to update the enabled/disabled state of CSpinButtonCtrlEx
//when contents of buddy window is changing.
//For instance, if user enters into buddy window the value greater
//than upper possible limit - it is obvious that the increasing
//arrow should switch to disable state.
//The best way to do it is to create WH_CALLWNDPROC hook
//and test within it if EN_UPDATE message came from buddy window
//Another posibility- keyboard hook, but then the user can foolish
//the control, using clipboard Copy/Cut/Paste functions.
//Test if WH_CALLWNDPROC hook already was installed.
// If no, set up it.
if(ghHook==NULL)
ghHook=SetWindowsHookEx(WH_CALLWNDPROC,FilterBuddyMsgProc,NULL, //WH_GETMESSAGE
GetCurrentThreadId());
//As so I use a single WH_CALLWNDPROC hook for all existing in
//an application CSpinButtonCtrlEx controls, I need to distinguish
// between these controls in the static FilterBuddyMsgProc.
//For this purpose I use static std:map<HWND,HWND> gHandleMap
//Try to find m_hWndBuddy in the gHandleMap
HWNDMAP::iterator iterHwnd=gHandleMap.find(m_hWndBuddy);
if(iterHwnd != gHandleMap.end())
{
if((*iterHwnd).second != m_hWnd)
{
//If in the gHandleMap already defined another CSpinButtonCtrlEx
//for that buddy (m_hWndBuddy), then redefine it .
gHandleMap.erase(iterHwnd);
gHandleMap.insert(HWNDMAP::value_type(m_hWndBuddy,m_hWnd));
}
}
else
//If the CSpinButtonCtrlEx assosiated with
//m_hWndBuddy is not found in the gHandleMap, then add it.
gHandleMap.insert(HWNDMAP::value_type(m_hWndBuddy,m_hWnd));
}
}
Invalidate(FALSE);
}
}
BOOL CSpinButtonCtrlEx::OnDeltapos(NMHDR* pNMHDR, LRESULT* pResult)
{
if(m_bAutoDisable)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
int nNextPos=pNMUpDown->iPos+pNMUpDown->iDelta;
//Determine the enable/disable state of CSpinButtonCtrlEx
if(nNextPos > m_nMaxPos)
nNextPos = m_nMaxPos;
else
{
if(nNextPos < m_nMinPos)
nNextPos = m_nMinPos;
}
if(m_nPrevPos!=nNextPos)
{
if(pNMUpDown->iDelta)
m_bActiveSpinPressed=true;
if(nNextPos <m_nMaxPos && nNextPos >m_nMinPos)
{
m_nSpinState = BothEnable;
}
else
{
if(nNextPos == m_nMaxPos)
{
if(m_nMaxPos != m_nMinPos)
{
m_nSpinState=DisableRight;
m_bActiveSpinPressed=false;
}
else
{
m_nSpinState = BothDisable;
m_bActiveSpinPressed=false;
}
}
else
{
if(nNextPos == m_nMinPos)
{
m_nSpinState=DisableLeft;
m_bActiveSpinPressed=false;
}
}
}
m_nPrevPos=nNextPos;
Invalidate(FALSE);
//Let the Windows process UDN_DELTAPOS too
*pResult = 0;
return FALSE;
}
else
{
//If the next position of control is the same as current,
//what can happen when user clicked the disable arrow,
//then eat UDN_DELTAPOS
*pResult = 1;
return TRUE;
}
}
else
{
//Let the Windows process UDN_DELTAPOS
*pResult = 0;
return FALSE;
}
}
LRESULT CSpinButtonCtrlEx::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
//Let the Windows do it's work
LRESULT nRet = CSpinButtonCtrl::WindowProc(message, wParam, lParam);
switch(message)
{
case UDM_SETRANGE32:
case UDM_SETRANGE:
//Need to reinit CSpinButtonCtrlEx, as so the
//limits probably changed
Init();
break;
case UDM_SETBUDDY :
//Need to reinit CSpinButtonCtrlEx, as so the
//buddy changed
CleanUpHook();
Init();
//If buddy window(m_hWndBuddy) is placed after this
//CSpinButtonCtrlEx in Z-order , then m_hWndBuddywindow will
//get WM_PAINT message after this CSpinButtonCtrlEx control
//and in case CSpinButtonCtrlEx is attached to buddy,
// it will be overpainted by buddy's border
//This undocumented bug persist for CSpinButtonCtrl as well.
//
//To reproduce it create on dialog template attached
//CSpinButtonCtrl control and CEdit control and make
//tab order so, that for CSpinButtonCtrl tab position
//was less then for CEdit;
//Then in OnInitDiaolg call SetBuddy(pointerToEdit) function
//of CSpinButtonCtrl.
//
//
//To work around this simply place CSpinButtonCtrl
//after it's buddy in Z-order.
if(::IsWindow(m_hWndBuddy))
::SetWindowPos(m_hWnd,m_hWndBuddy,0,0,0,0,
SWP_NOMOVE|SWP_NOSIZE);
break;
}
return nRet;
}
void CSpinButtonCtrlEx::CleanUpHook() const
{
if(m_bBuddyIsEdit)
{
//If the buddy is edit, then try to find out if
//it was added to gHandleMap.
HWNDMAP::iterator iterHwnd=gHandleMap.find(m_hWndBuddy);
if(iterHwnd != gHandleMap.end() && (*iterHwnd).second == m_hWnd)
{
//If m_hWndBuddy found and is assosiated with current window,
//then delete it from gHandleMap.
iterHwnd = gHandleMap.erase(iterHwnd);
if(!gHandleMap.size() && ghHook!=NULL)
{
//If just deleted from the gHandleMap m_hWndBuddy was
//the last for current application,
//then remove a hook procedure.
UnhookWindowsHookEx( ghHook);
ghHook=NULL;
}
}
}
}
void CSpinButtonCtrlEx::OnLButtonDown(UINT nFlags, CPoint point)
{
m_rctIsPressed.SetRectEmpty();
CSpinButtonCtrl::OnLButtonDown(nFlags, point);
}
BOOL CSpinButtonCtrlEx::OnEraseBkgnd(CDC* pDC)
{
return TRUE ; //Get rid of flickering
}
void CSpinButtonCtrlEx::OnLButtonUp(UINT nFlags, CPoint point)
{
Invalidate();
UpdateWindow();
CSpinButtonCtrl::OnLButtonUp(nFlags, point);
}
bool CSpinButtonCtrlEx::SetAutoDisable(bool bSetOn)
{
// User should have an opportunity to swith on/off the custom
//behavior of the CSpinButtonCtrlEx control.
bool bPrev = m_bAutoDisable;
m_bAutoDisable = bSetOn;
Init();
return bPrev;
}
LRESULT CALLBACK FilterBuddyMsgProc( int code, WPARAM wParam, LPARAM lParam )
{
CWPSTRUCT* pData=reinterpret_cast<CWPSTRUCT*>(lParam);
if(WM_COMMAND==pData->message && EN_UPDATE==HIWORD(pData->wParam))
{
//If the incoming message is EN_UPDATE
HWNDMAP::iterator iterHwnd=gHandleMap.find(reinterpret_cast<HWND>(pData->lParam));
if(iterHwnd != gHandleMap.end())
{
//The incoming EN_UPDATE message has been sent
//to the edit control, defined in the gHandleMap.
//So get the value, entered into the edit control
//and send it to the CSpinButtonCtrlEx, assosiated
//with the edit control.
CString strText;
int nLen=::GetWindowTextLength((*iterHwnd).first);
::GetWindowText((*iterHwnd).first,strText.GetBufferSetLength(nLen),nLen+1);
strText.ReleaseBuffer();
//In case UDS_NOTHOUSANDS style not applied
//we have to delete thousands delimiter from string
strText.Remove((TCHAR)0xA0);
NMUPDOWN nmUpDn;
nmUpDn.iDelta=0;
nmUpDn.iPos=_tstoi(strText);
nmUpDn.hdr.code=UDN_DELTAPOS;
nmUpDn.hdr.hwndFrom=(*iterHwnd).second;
nmUpDn.hdr.idFrom=::GetDlgCtrlID((*iterHwnd).second);
HWND hWndSpinParent=::GetParent((*iterHwnd).second);
::SendMessage(::GetParent((*iterHwnd).second),
WM_NOTIFY,(WPARAM)nmUpDn.hdr.idFrom,
(LPARAM)&nmUpDn);
}
}
return CallNextHookEx(ghHook,code,wParam,lParam);
}
void CSpinButtonCtrlEx::OnDestroy()
{
//Remove current CSpinButtonCtrlEx control from the gHandleMap and
//if it is the last control, defined in the gHandleMap
//then remove a hook procedure.
CleanUpHook();
CSpinButtonCtrl::OnDestroy();
}
#endif
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -