www.pudn.com > year_month_selector.zip > YMSelector.cpp


// YMSelector.cpp : implementation file 
// Control to select year and month 
// Designed and developed by Shekar Narayanan, 4th July 1998 
// ShekarNarayanan@Hotmail.com 
//  
// Modified : Jeremy Davis, 3rd December 1998 
//            jmd@jvf.co.uk 
// 
// Changes : 
//	(03/12/98) 
//	- Month / Year  display window more "3D" 
//	- "Cool-look" flat button for "+" and "-" buttons 
//	- Dropdown button enlarged to match height of month/Year display window 
//	- Colour of popup window changed 
//  - Cell borders removed 
//	- 3D borders added to popup window and "+" and "-" buttons 
//	- Cursor / Arrow keys now move month selection in popup window 
//	-  /  within the popup window now choose the selection 
//  - Keith Rule's (keithr@europa.com) CMemDC class used to stop flickering 
// 
// Future Changes / Additions : 
//	- Click outside popup window cause the same action as  
 
 
 
#include "stdafx.h" 
#include "YMSelector.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
 
static char *Months[] = 
{ 
    "一月", 
    "二月", 
    "三月", 
    "四月", 
    "五月", 
    "六月", 
    "七月", 
    "八月", 
    "九月", 
    "十月", 
    "十一月", 
    "十二月" 
}; 
 
///////////////////////////////////////////////////////////////////////////// 
// CYMPopUp 
 
CYMPopUp::CYMPopUp(CPoint p, CWnd* pParent, int nYear, int nMonth)  
: m_bkBrush(::GetSysColor(COLOR_INFOBK)) 
{ 
    if  (-1 == nYear) 
        m_nYear     = CTime::GetCurrentTime().GetYear(); 
    else 
        m_nYear     = nYear; 
 
    if  (-1 == nMonth) 
        m_nMonth    = CTime::GetCurrentTime().GetMonth() -1; 
    else 
        m_nMonth    = nMonth -1; 
 
	m_inPlus	= FALSE; 
	m_inMinus = FALSE; 
 
    ASSERT(m_nYear >= START_YEAR && m_nYear <= END_YEAR); 
    ASSERT(m_nMonth >= 0   && m_nMonth <= 11 ); 
 
    Create(p, pParent); 
} 
 
 
CYMPopUp::~CYMPopUp() 
{ 
    m_bkBrush.DeleteObject(); 
} 
 
 
BEGIN_MESSAGE_MAP(CYMPopUp, CWnd) 
	//{{AFX_MSG_MAP(CYMPopUp) 
	ON_WM_NCDESTROY() 
	ON_WM_LBUTTONUP() 
	ON_WM_PAINT() 
	ON_WM_LBUTTONDOWN() 
	ON_WM_KEYDOWN() 
	ON_WM_ERASEBKGND() 
	ON_WM_MOUSEMOVE() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CYMPopUp message handlers 
 
 
BOOL CYMPopUp::Create(CPoint p, CWnd* pParent) 
{ 
    m_pParent = pParent; 
    ASSERT(m_pParent); 
 
    CString szClassName = AfxRegisterWndClass(CS_CLASSDC|CS_SAVEBITS|CS_HREDRAW|CS_VREDRAW, 
                                              0, (HBRUSH)m_bkBrush,0); 
 
    if (!CWnd::CreateEx(0, szClassName, _T(""), WS_VISIBLE|WS_POPUP/*|WS_BORDER*/,  
                        p.x, p.y, 200, 100,  
                        pParent->GetSafeHwnd(), 0, NULL)) 
        return FALSE; 
 
    m_pParent->EnableWindow(false); 
 
    UpdateWindow(); 
 
 
    return TRUE; 
} 
 
void CYMPopUp::OnNcDestroy()  
{ 
	CWnd::OnNcDestroy(); 
    delete this; 
	 
	 
} 
 
 
void CYMPopUp::OnPaint()  
{ 
	CPaintDC	PaintDC(this); 
	CMemDC		dc(&PaintDC); 
    CString     Buffer; 
    CRect       rClient; 
    CRect       rCell; 
    CRect       rStart; 
    CFont       fText; 
    CFont*      pfdc; 
    short       nCellHeight; 
    short       nCellWidth; 
    short       nIndex = 0; 
 
 
    GetClientRect(rClient); 
	dc.FillSolidRect(rClient, ::GetSysColor(COLOR_BTNFACE)); 
	dc.DrawEdge(rClient, EDGE_RAISED, BF_RECT); 
    rClient.DeflateRect(2,2); 
 
    m_rMinus.CopyRect(rClient); 
	m_rMinus.left	= rClient.left + 1; 
	m_rMinus.top	= rClient.top + 1; 
    m_rMinus.right  = m_rMinus.left + 30; 
    m_rMinus.bottom = m_rMinus.top + 16; 
 
    m_rPlus.CopyRect(rClient); 
	m_rPlus.right	= rClient.right - 1; 
	m_rPlus.top		= rClient.top + 1; 
    m_rPlus.left    = m_rPlus.right - 30; 
    m_rPlus.bottom  = m_rPlus.top + 16; 
 
    m_rYear.CopyRect(rClient); 
    m_rYear.left    = m_rMinus.right + 5; 
    m_rYear.right   = m_rPlus.left   - 5; 
    m_rYear.bottom  = m_rYear.top    + 20; 
	 
    fText.DeleteObject(); 
    fText.CreateFont(-12, 0, 0, 0, 700, 0, 0, 0, 1, 0, 0, DRAFT_QUALITY, 0, _T("MS Sans Serif") ); 
    pfdc = dc.SelectObject(&fText); 
 
    dc.SetBkColor(::GetSysColor(COLOR_BTNFACE)); 
    dc.SetTextColor(::GetSysColor(COLOR_BTNTEXT)); 
 
	dc.SetBkMode(TRANSPARENT); 
    Buffer.Format("%d", m_nYear); 
    dc.DrawText(Buffer, m_rYear, DT_CENTER|DT_VCENTER|DT_SINGLELINE); 
 
 
	if (m_inMinus) 
		dc.DrawEdge(&m_rMinus, EDGE_RAISED, BF_RECT); 
	if (m_inPlus) 
		dc.DrawEdge(&m_rPlus, EDGE_RAISED, BF_RECT); 
 
	dc.SelectObject(pfdc); 
    fText.DeleteObject(); 
    fText.CreatePointFont(80,"MS Sans Serif"); 
	pfdc = dc.SelectObject(&fText); 
 
    dc.DrawText("<<", m_rMinus, DT_CENTER|DT_VCENTER|DT_SINGLELINE); 
    dc.DrawText(">>", m_rPlus, DT_CENTER|DT_VCENTER|DT_SINGLELINE); 
    dc.SetBkMode(OPAQUE); 
 
     
 
    nCellHeight     = rClient.Height() / 5; 
    nCellWidth      = rClient.Width() / 3; 
 
    rCell.left      = rClient.left; 
    rCell.top       = rClient.top + nCellHeight; 
    rCell.right     = rCell.left  + nCellWidth; 
    rCell.bottom    = rCell.top   + nCellHeight; 
 
    rStart.CopyRect(rCell); 
    for (int i = 0; i < 4; i++) 
    { 
        for (int j = 0; j < 3; j++) 
        { 
            CRect   rCurSel(rCell); 
             
            if  ( m_nMonth == nIndex ) 
            { 
                dc.FillSolidRect(rCurSel,::GetSysColor(COLOR_HIGHLIGHT)); 
                dc.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT)); 
            } 
            else 
            { 
                dc.FillSolidRect(rCurSel,::GetSysColor(COLOR_BTNFACE)); 
                dc.SetTextColor(::GetSysColor(COLOR_BTNTEXT)); 
            } 
 
            dc.DrawText(Months[nIndex], rCell, DT_VCENTER|DT_CENTER|DT_SINGLELINE); 
            m_rCells[nIndex].CopyRect(rCell); 
 
            rCell.OffsetRect(nCellWidth,0); 
            nIndex++; 
        } 
 
        rStart.OffsetRect(0,nCellHeight); 
        rCell.CopyRect(rStart); 
    } 
 
    dc.SelectObject(pfdc); 
    fText.DeleteObject(); 
 
} 
 
void CYMPopUp::OnLButtonDown(UINT nFlags, CPoint point)  
{ 
    CClientDC   dc(this); 
	CWnd::OnLButtonDown(nFlags, point); 
 
    for (int i = 0; i < 12; i++) 
    { 
        if  (m_rCells[i].PtInRect(point)) 
        { 
            InvalidateRect(m_rCells[m_nMonth]); 
            m_nMonth = i; 
            InvalidateRect(m_rCells[i]); 
            return; 
        } 
    } 
 
    if  (m_rMinus.PtInRect(point)) 
        dc.InvertRect(m_rMinus); 
 
    if  (m_rPlus.PtInRect(point)) 
        dc.InvertRect(m_rPlus); 
 
} 
 
void CYMPopUp::OnLButtonUp(UINT nFlags, CPoint point)  
{ 
    CClientDC   dc(this); 
    CRect       rClient; 
    int         nCellHeight; 
 
    if  (m_rMinus.PtInRect(point)) 
    { 
        m_nYear--;  
		if   (m_nYear < START_YEAR)m_nYear = START_YEAR; 
        dc.InvertRect(m_rMinus); 
        InvalidateRect(m_rYear); 
        return; 
    } 
 
    if  (m_rPlus.PtInRect(point)) 
    { 
        m_nYear++; if   (m_nYear > END_YEAR)m_nYear = END_YEAR; 
        dc.InvertRect(m_rPlus); 
        InvalidateRect(m_rYear); 
        return; 
    } 
 
 
 
    GetClientRect(rClient); 
    rClient.DeflateRect(2,2); 
 
    nCellHeight     = rClient.Height() / 5; 
    rClient.top += nCellHeight; 
 
    if  (rClient.PtInRect(point)) 
    { 
        m_pParent->EnableWindow(true); 
        m_pParent->PostMessage(YM_SELECTED, (WPARAM)m_nYear, (LPARAM)m_nMonth); 
        DestroyWindow(); 
    } 
 
} 
 
 
void CYMPopUp::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)  
{ 
	CWnd::OnKeyDown(nChar, nRepCnt, nFlags); 
	switch(nChar) 
	{ 
	case VK_ESCAPE: 
		m_pParent->EnableWindow(true); 
        m_pParent->SendMessage(YM_ABORTED); 
        DestroyWindow(); 
		break; 
	case VK_RIGHT: 
		m_nMonth++; 
		if(m_nMonth == 12) 
		{ 
			m_nMonth = 0; 
			m_nYear++; 
		} 
		Invalidate(); 
		break; 
	case VK_LEFT: 
		m_nMonth--; 
		if(m_nMonth < 0) 
		{ 
			m_nMonth = 11; 
			m_nYear--; 
		} 
		Invalidate(); 
		break; 
	case VK_UP: 
		m_nMonth -= 3; 
		if(m_nMonth < 0) 
		{ 
			m_nMonth += 12; 
			m_nYear--; 
		} 
		Invalidate(); 
		break; 
	case VK_DOWN: 
		m_nMonth += 3; 
		if (m_nMonth > 11) 
		{ 
			m_nMonth -= 12; 
			m_nYear++; 
		} 
		Invalidate(); 
		break; 
	case VK_SPACE: 
	case VK_RETURN: 
		m_pParent->EnableWindow(true); 
        m_pParent->PostMessage(YM_SELECTED, (WPARAM)m_nYear, (LPARAM)m_nMonth); 
        DestroyWindow(); 
		break; 
    } 
	 
} 
 
BOOL CYMPopUp::OnEraseBkgnd(CDC* pDC)  
{	 
 	return FALSE; 
} 
 
void CYMPopUp::OnMouseMove(UINT nFlags, CPoint point)  
{ 
	// TODO: Add your message handler code here and/or call default 
	CClientDC   dc(this); 
    BOOL oinPlus	= m_inPlus; 
	BOOL oinMinus	= m_inMinus; 
 
    if  (m_rMinus.PtInRect(point)) 
		m_inMinus = TRUE; 
	else 
		m_inMinus = FALSE; 
 
    if  (m_rPlus.PtInRect(point)) 
		m_inPlus = TRUE; 
	else 
		m_inPlus = FALSE; 
 
	if (oinMinus != m_inMinus) 
		InvalidateRect(&m_rMinus); 
 
	if (oinPlus != m_inPlus) 
		InvalidateRect(&m_rPlus); 
 
	CWnd::OnMouseMove(nFlags, point); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// CYMSelector 
 
CYMSelector::CYMSelector() 
{ 
    m_nMonth = CTime::GetCurrentTime().GetMonth(); 
    m_nYear  = CTime::GetCurrentTime().GetYear(); 
} 
 
CYMSelector::~CYMSelector() 
{ 
} 
 
 
BEGIN_MESSAGE_MAP(CYMSelector, CButton) 
	//{{AFX_MSG_MAP(CYMSelector) 
	ON_CONTROL_REFLECT(BN_CLICKED, OnClicked) 
	//}}AFX_MSG_MAP 
    ON_MESSAGE(YM_SELECTED, YMSelected) 
    ON_MESSAGE(YM_ABORTED,  YMAborted) 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CYMSelector message handlers 
 
void CYMSelector::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)  
{ 
    ASSERT(lpDrawItemStruct); 
 
    CString BtnText; 
    CDC*    pDC     = CDC::FromHandle(lpDrawItemStruct->hDC); 
    CRect   rect    = lpDrawItemStruct->rcItem; 
    UINT    state   = lpDrawItemStruct->itemState; 
     
    CRect   rArrow(rect); 
 
    rArrow.left    = rArrow.right - 20; 
	rArrow.InflateRect(0, 1); 
 
    CSize Margins(::GetSystemMetrics(SM_CXEDGE), ::GetSystemMetrics(SM_CYEDGE)); 
 
    pDC->DrawFrameControl(&rArrow, DFC_SCROLL, DFCS_SCROLLDOWN  |  
                          ((state & ODS_SELECTED) ? DFCS_PUSHED : 0) | 
                          ((state & ODS_DISABLED) ? DFCS_INACTIVE : 0)); 
 
 
    rect.right -= rArrow.Width(); 
 
    pDC->FillSolidRect(rect,::GetSysColor(COLOR_WINDOW)); 
 
    GetWindowText(BtnText); 
    if  (state & ODS_DISABLED) 
        pDC->SetTextColor(::GetSysColor(COLOR_GRAYTEXT)); 
    else 
        pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT)); 
 
    pDC->DrawText(BtnText, rect, DT_CENTER|DT_SINGLELINE|DT_VCENTER); 
 
    if (state & ODS_FOCUS)  
    { 
        rect.DeflateRect(2,2); 
        pDC->DrawFocusRect(rect); 
		rect.InflateRect(2,2); 
    } 
 
    rect.InflateRect(1,1); 
    pDC->DrawEdge(rect,EDGE_SUNKEN,BF_RECT); 
	rect.DeflateRect(1,1); 
    pDC->DrawEdge(rect,EDGE_SUNKEN,BF_RECT); 
	 
} 
 
void CYMSelector::PreSubclassWindow()  
{ 
	CButton::PreSubclassWindow(); 
    CString buffer; 
    CTime   tCurrent = CTime::GetCurrentTime(); 
    buffer = tCurrent.Format("%B, %Y"); 
    SetWindowText(buffer); 
 
    m_nYear  = tCurrent.GetYear(); 
    m_nMonth = tCurrent.GetMonth() - 1; 
} 
 
void CYMSelector::OnClicked()  
{ 
    CRect rect; 
    GetWindowRect(rect); 
    rect.OffsetRect(0,rect.Height()); 
    GetParent()->EnableWindow(false); 
 
    new CYMPopUp(CPoint(rect.left,rect.top), this,GetYear(),GetMonth()); 
 
    return; 
 
} 
 
 
LONG CYMSelector::YMSelected(WPARAM wParam , LPARAM lParam ) 
{ 
    m_nYear   = (int) wParam; 
    m_nMonth  = (int)lParam; 
 
    CString buffer; 
    buffer.Format("%s, %d", GetMonthString(), GetYear()); 
    SetWindowText(buffer); 
    GetParent()->EnableWindow(true); 
    GetParent()->SetFocus(); 
 
    return 0; 
} 
 
LONG CYMSelector::YMAborted(WPARAM wParam , LPARAM lParam ) 
{ 
    GetParent()->EnableWindow(true); 
    GetParent()->SetFocus(); 
 
    return 0; 
} 
 
int CYMSelector::GetYear() 
{ 
    return m_nYear; 
} 
 
int CYMSelector::GetMonth() 
{ 
    return m_nMonth + 1; 
} 
 
LPCTSTR CYMSelector::GetMonthString() 
{ 
    return Months[m_nMonth]; 
} 
 
void CYMSelector::SetMonth(int m) 
{ 
    m--; 
    ASSERT(m >= 0 && m <= 11); 
    m_nMonth = m; 
 
    CString buffer; 
    buffer.Format("%s, %d", GetMonthString(), GetYear()); 
    SetWindowText(buffer); 
} 
 
 
void CYMSelector::SetYear(int y) 
{ 
 
    ASSERT( y >= START_YEAR && y <= END_YEAR); 
    m_nYear = y; 
 
    CString buffer; 
    buffer.Format("%s, %d", GetMonthString(), GetYear()); 
    SetWindowText(buffer); 
}