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); }