#include "StdAfx.h" #include "MaskEdit.h" #include // 跟日期输入控件的格式相关的字符串常量 // 注意:函数CDateEdit::ProcessMask的代码和日期格式有关联 static LPCTSTR lpszDateMask = _T("0000-00-00"); static LPCTSTR lpszDateLiteral = _T("____-__-__"); static LPCTSTR lpszDateFormat = _T("%Y-%m-%d"); // 跟时间输入控件的格式相关的字符串常量 // 注意:函数CTimeEdit::ProcessMask的代码和时间格式有关联 static LPCTSTR lpszTime1Mask = _T("00:00:00"); // 包含“秒” static LPCTSTR lpszTime1Literal = _T("__:__:__"); static LPCTSTR lpszTime1Format = _T("%H:%M:%S"); static LPCTSTR lpszTime2Mask = _T("00:00"); // 不包含“秒” static LPCTSTR lpszTime2Literal = _T("__:__"); static LPCTSTR lpszTime2Format = _T("%H:%M"); ///////////////////////////////////////////////////////////////////////////// // CMaskEdit class ///////////////////////////////////////////////////////////////////////////// CMaskEdit::CMaskEdit( ) { } IMPLEMENT_DYNAMIC(CMaskEdit, CEdit) BEGIN_MESSAGE_MAP(CMaskEdit, CEdit) ON_MASKEDIT_REFLECT() END_MESSAGE_MAP() void CMaskEdit::SetEditMask(LPCTSTR lpszMask,LPCTSTR lpszLiteral,LPCTSTR lpszDefault /*=NULL*/) { CMaskEditT::SetEditMask(lpszMask, lpszLiteral, lpszDefault); } ///////////////////////////////////////////////////////////////////////////// // CDateEdit class ///////////////////////////////////////////////////////////////////////////// CDateEdit::CDateEdit( ) { m_bUseMask = TRUE; m_strMask = lpszDateMask; m_strLiteral = lpszDateLiteral; } IMPLEMENT_DYNAMIC(CDateEdit, CMaskEdit) CString CDateEdit::DateToString(COleDateTime dt) { // 如果输入的COleDateTime对象不合法,则使用缺省构造函数产生的日期 if (dt.GetStatus() == COleDateTime::valid) return dt.Format(lpszDateFormat); else return COleDateTime().Format(lpszDateFormat); } COleDateTime CDateEdit::StringToOleDateTime(CString strText, TCHAR chPrompt) { // 删除文本中的提示字符 CString strPromptChar(chPrompt); strText.Replace(strPromptChar, NULL); // 从文本中获取日期/时间 COleDateTime dt; dt.ParseDateTime(strText); return dt; } void CDateEdit::SetDateTime(COleDateTime dt) { m_strWindowText = DateToString(dt); SetWindowText(m_strWindowText); } COleDateTime CDateEdit::GetDateTime( ) { CString strText; GetWindowText(strText); COleDateTime dt = StringToOleDateTime(strText, m_chPrompt); if (dt.GetStatus() == COleDateTime::valid) SetDateTime(dt); return dt; } BOOL CDateEdit::ProcessMask(UINT& nChar,int nEndPos) { // check the key against the mask switch ( m_strMask.GetAt( nEndPos ) ) { case '0': // digit only //completely changed this { BOOL bReturn = TRUE; if ( _istdigit( ( TCHAR )nChar ) ) { if ( nEndPos == 8 ) // 日期的十位 { if ( nChar > '3' ) { bReturn = FALSE; } } else if ( nEndPos == 9 ) // 日期的个位 { if ( m_strWindowText.GetAt(8) == '3' ) { if ( nChar > '1' ) { bReturn = FALSE; } } } else if ( nEndPos == 5 ) // 月份的十位 { if ( nChar > '1' ) { bReturn = FALSE; } } else if ( nEndPos == 6 ) // 月份的个位 { if ( m_strWindowText.GetAt(5) == '1' ) { if ( nChar > '2') { bReturn = FALSE; } } } return bReturn; } break; } } return FALSE; } ///////////////////////////////////////////////////////////////////////////// // CTimeEdit class ///////////////////////////////////////////////////////////////////////////// CTimeEdit::CTimeEdit(BOOL bHasSecond /* = FALSE */ ) { m_bHasSecond = bHasSecond; m_bUseMask = TRUE; m_strMask = m_bHasSecond ? lpszTime1Mask : lpszTime2Mask; m_strLiteral = m_bHasSecond ? lpszTime1Literal : lpszTime2Literal; } IMPLEMENT_DYNAMIC(CTimeEdit, CDateEdit) CString CTimeEdit::TimeToString(COleDateTime dt, BOOL bHasSecond /* = FALSE */ ) { // 如果输入的COleDateTime对象不合法,则使用缺省构造函数产生的时间 LPCTSTR lpsz = bHasSecond ? lpszTime1Format : lpszTime2Format; if (dt.GetStatus() == COleDateTime::valid) return dt.Format(lpsz); else return COleDateTime().Format(lpsz); } void CTimeEdit::SetDateTime(COleDateTime dt) { m_strWindowText = TimeToString(dt, m_bHasSecond); SetWindowText(m_strWindowText); } BOOL CTimeEdit::ProcessMask(UINT& nChar,int nEndPos) { // check the key against the mask switch ( m_strMask.GetAt( nEndPos ) ) { case '0': // digit only //completely changed this { if ( _istdigit( (TCHAR)nChar ) ) { switch (nEndPos) { case 0: // 小时的十位 if (nChar > '2') { return FALSE; } break; case 1: // 小时的个位 if (m_strWindowText.GetAt(0) == '2' && nChar > '3') { return FALSE; } break; case 3: // 分钟的十位 if (nChar > '5') { return FALSE; } break; case 4: // 分钟的个位 if (nChar > '9') { return FALSE; } break; case 6: // 秒的十位 if (nChar > '5') { return FALSE; } break; case 7: // 秒的个位 if (nChar > '9') { return FALSE; } break; } return TRUE; } break; } } return FALSE; } ///////////////////////////////////////////////////////////////////////////// // 类 CDegreeEdit ///////////////////////////////////////////////////////////////////////////// CDegreeEdit::CDegreeEdit(int nSecondPrecision /* = 2 */) { // 确保秒的小数部分的位数在有效范围之内 const int nMinPrecision = 0; // 最小有效位数 const int nMaxPrecision = 3; // 最大有效位数 ASSERT(nSecondPrecision >= nMinPrecision && nSecondPrecision <= nMaxPrecision); m_nSecondPrecision = nSecondPrecision; if (m_nSecondPrecision < nMinPrecision) { m_nSecondPrecision = nMinPrecision; } else if (m_nSecondPrecision > nMaxPrecision) { m_nSecondPrecision = nMaxPrecision; } m_chPrompt = _T(' '); // 使用空格做提示字符 if (m_nSecondPrecision == 0) { m_strMask = _T("#000°00'00\""); m_strLiteral = _T(" ° ' \""); } else { m_strMask = _T("#000°00'00.") + CString(_T('0'), m_nSecondPrecision) + _T('\"'); m_strLiteral = _T(" ° ' .") + CString(_T(' '), m_nSecondPrecision) + _T('\"'); } } IMPLEMENT_DYNAMIC(CDegreeEdit, CMaskEdit) void CDegreeEdit::SetDegree(double fDegree) { // 以度分秒的格式显示度 m_strWindowText = CDegreeEdit::DegreeToString(fDegree, m_nSecondPrecision); SetWindowText( m_strWindowText ); } double CDegreeEdit::GetDegree() { CString strText; GetWindowText(strText); // 读取数据 double fDegree = CDegreeEdit::StringToDegree(strText); SetDegree(fDegree); return fDegree; } CString CDegreeEdit::DegreeToString(double fDegree, int nSecondPrecision /* = 2 */) { // 计算度分秒 int degree, minute; double second; double temp = fabs(fDegree)+(1E-6/3600);// 由于浮点数存在舍入误差,可能给取整计算度和分 degree = (int)temp; // 带来问题。例如10.7表示为 double 类型时,其值 temp = (temp-degree) * 60; // 为10.699...99,取整得到的度等于10,分等于41, minute = (int)temp; // 秒用格式%05.2f输出得到60.00。这显然不合理。 second = (temp-minute) * 60; // 如果加一个很小的数,既能解决这个问题,又不会 // 影响数值的精确度。这里加的是百万分之一秒。 // 生成度分秒格式的文本 CString strFormat; // 格式字符串 CString strMaxSecond; // 秒的最大值(文本格式) if (nSecondPrecision == 0) { strFormat = _T("%3d°%02d'%02.0f\""); strMaxSecond = _T("59"); } else { strFormat.Format( _T("%%3d°%%02d'%%0%d.%df\""), 3+nSecondPrecision, nSecondPrecision); strMaxSecond = _T("59.") + CString(_T('9'), nSecondPrecision); } #ifdef _UNICODE char ansi_buf[256]; ::WideCharToMultiByte(CP_ACP, 0, strMaxSecond, -1, ansi_buf, 256, NULL, NULL); double fMaxSecond = atof(ansi_buf); // 秒的最大值(浮点数格式) #else double fMaxSecond = atof(strMaxSecond); // 秒的最大值(浮点数格式) #endif CString strText; strText.Format( strFormat, min(999,degree), // 不超出999 minute, min(fMaxSecond,second) ); // 避免出现类似59.999"被格式化输出成60.00"的情况 if (fDegree >= 0) strText = _T(' ') + strText; else strText = _T('-') + strText; return strText; } double CDegreeEdit::StringToDegree(CString strText) { // 删除文本中的提示字符 CString strPromptChar( _T(' ') ); strText.Replace(strPromptChar, NULL); // 读取数据 int degree = 0, minute = 0; float second = 0; #ifdef _UNICODE char ansi_buf[256]; ::WideCharToMultiByte(CP_ACP, 0, strText, -1, ansi_buf, 256, NULL, NULL); sscanf(ansi_buf, "%d°%d'%f", °ree, &minute, &second); #else sscanf(strText, "%d°%d'%f", °ree, &minute, &second); #endif double fDegree = abs(degree) + minute/60.0 + second/3600.0; fDegree = min(999, fDegree); // 不超出999 if (strText.Find( _T('-') ) >= 0) fDegree = -fDegree; return fDegree; } ///////////////////////////////////////////////////////////////////////////// // DDX_ routines ///////////////////////////////////////////////////////////////////////////// void AFXAPI DDX_OleDateTime(CDataExchange* pDX, int nIDC, COleDateTime& rDateTime) { // 从控件ID获取CDateEdit对象指针 HWND hControl = ::GetDlgItem(pDX->m_pDlgWnd->m_hWnd, nIDC); CWnd* pControl = CWnd::FromHandlePermanent(hControl); ASSERT(pControl); ASSERT(pControl->IsKindOf(RUNTIME_CLASS(CDateEdit))); CDateEdit* pDateEdit = (CDateEdit*)pControl; // 进行数据交换 if ( pDX->m_bSaveAndValidate ) { COleDateTime dt = pDateEdit->GetDateTime( ); if (dt.GetStatus() != COleDateTime::valid) { if (pDateEdit->IsKindOf(RUNTIME_CLASS(CTimeEdit))) // 时间编辑控件 AfxMessageBox( _T("请键入一个合法的时间。") ); else // 日期编辑控件 AfxMessageBox( _T("请键入一个合法的日期。") ); pDX->PrepareCtrl(nIDC); pDX->Fail(); // 该函数把输入焦点传给控件,然后抛出一个异常 } rDateTime = dt; } else { pDateEdit->SetDateTime( rDateTime ); } } void AFXAPI DDX_Degree(CDataExchange* pDX, int nIDC, double& value) { // 从控件ID获取CDegreeEdit对象指针 HWND hControl = ::GetDlgItem(pDX->m_pDlgWnd->m_hWnd, nIDC); CWnd* pControl = CWnd::FromHandlePermanent(hControl); ASSERT(pControl); ASSERT(pControl->IsKindOf(RUNTIME_CLASS(CDegreeEdit))); CDegreeEdit* pDegreeEdit = (CDegreeEdit*)pControl; // 进行数据交换 if ( pDX->m_bSaveAndValidate ) { value = pDegreeEdit->GetDegree(); } else { pDegreeEdit->SetDegree( value ); } }