MaskEdit.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. #include "StdAfx.h"
  2. #include "MaskEdit.h"
  3. #include <math.h>
  4. // 跟日期输入控件的格式相关的字符串常量
  5. // 注意:函数CDateEdit::ProcessMask的代码和日期格式有关联
  6. static LPCTSTR lpszDateMask = _T("0000-00-00");
  7. static LPCTSTR lpszDateLiteral = _T("____-__-__");
  8. static LPCTSTR lpszDateFormat = _T("%Y-%m-%d");
  9. // 跟时间输入控件的格式相关的字符串常量
  10. // 注意:函数CTimeEdit::ProcessMask的代码和时间格式有关联
  11. static LPCTSTR lpszTime1Mask = _T("00:00:00"); // 包含“秒”
  12. static LPCTSTR lpszTime1Literal = _T("__:__:__");
  13. static LPCTSTR lpszTime1Format = _T("%H:%M:%S");
  14. static LPCTSTR lpszTime2Mask = _T("00:00"); // 不包含“秒”
  15. static LPCTSTR lpszTime2Literal = _T("__:__");
  16. static LPCTSTR lpszTime2Format = _T("%H:%M");
  17. /////////////////////////////////////////////////////////////////////////////
  18. // CMaskEdit class
  19. /////////////////////////////////////////////////////////////////////////////
  20. CMaskEdit::CMaskEdit( )
  21. {
  22. }
  23. IMPLEMENT_DYNAMIC(CMaskEdit, CEdit)
  24. BEGIN_MESSAGE_MAP(CMaskEdit, CEdit)
  25. ON_MASKEDIT_REFLECT()
  26. END_MESSAGE_MAP()
  27. void CMaskEdit::SetEditMask(LPCTSTR lpszMask,LPCTSTR lpszLiteral,LPCTSTR lpszDefault /*=NULL*/)
  28. {
  29. CMaskEditT<CEdit>::SetEditMask(lpszMask, lpszLiteral, lpszDefault);
  30. }
  31. /////////////////////////////////////////////////////////////////////////////
  32. // CDateEdit class
  33. /////////////////////////////////////////////////////////////////////////////
  34. CDateEdit::CDateEdit( )
  35. {
  36. m_bUseMask = TRUE;
  37. m_strMask = lpszDateMask;
  38. m_strLiteral = lpszDateLiteral;
  39. }
  40. IMPLEMENT_DYNAMIC(CDateEdit, CMaskEdit)
  41. CString CDateEdit::DateToString(COleDateTime dt)
  42. {
  43. // 如果输入的COleDateTime对象不合法,则使用缺省构造函数产生的日期
  44. if (dt.GetStatus() == COleDateTime::valid)
  45. return dt.Format(lpszDateFormat);
  46. else
  47. return COleDateTime().Format(lpszDateFormat);
  48. }
  49. COleDateTime CDateEdit::StringToOleDateTime(CString strText, TCHAR chPrompt)
  50. {
  51. // 删除文本中的提示字符
  52. CString strPromptChar(chPrompt);
  53. strText.Replace(strPromptChar, NULL);
  54. // 从文本中获取日期/时间
  55. COleDateTime dt;
  56. dt.ParseDateTime(strText);
  57. return dt;
  58. }
  59. void CDateEdit::SetDateTime(COleDateTime dt)
  60. {
  61. m_strWindowText = DateToString(dt);
  62. SetWindowText(m_strWindowText);
  63. }
  64. COleDateTime CDateEdit::GetDateTime( )
  65. {
  66. CString strText;
  67. GetWindowText(strText);
  68. COleDateTime dt = StringToOleDateTime(strText, m_chPrompt);
  69. if (dt.GetStatus() == COleDateTime::valid)
  70. SetDateTime(dt);
  71. return dt;
  72. }
  73. BOOL CDateEdit::ProcessMask(UINT& nChar,int nEndPos)
  74. {
  75. // check the key against the mask
  76. switch ( m_strMask.GetAt( nEndPos ) )
  77. {
  78. case '0': // digit only //completely changed this
  79. {
  80. BOOL bReturn = TRUE;
  81. if ( _istdigit( ( TCHAR )nChar ) )
  82. {
  83. if ( nEndPos == 8 ) // 日期的十位
  84. {
  85. if ( nChar > '3' ) {
  86. bReturn = FALSE;
  87. }
  88. }
  89. else if ( nEndPos == 9 ) // 日期的个位
  90. {
  91. if ( m_strWindowText.GetAt(8) == '3' )
  92. {
  93. if ( nChar > '1' ) {
  94. bReturn = FALSE;
  95. }
  96. }
  97. }
  98. else if ( nEndPos == 5 ) // 月份的十位
  99. {
  100. if ( nChar > '1' ) {
  101. bReturn = FALSE;
  102. }
  103. }
  104. else if ( nEndPos == 6 ) // 月份的个位
  105. {
  106. if ( m_strWindowText.GetAt(5) == '1' )
  107. {
  108. if ( nChar > '2') {
  109. bReturn = FALSE;
  110. }
  111. }
  112. }
  113. return bReturn;
  114. }
  115. break;
  116. }
  117. }
  118. return FALSE;
  119. }
  120. /////////////////////////////////////////////////////////////////////////////
  121. // CTimeEdit class
  122. /////////////////////////////////////////////////////////////////////////////
  123. CTimeEdit::CTimeEdit(BOOL bHasSecond /* = FALSE */ )
  124. {
  125. m_bHasSecond = bHasSecond;
  126. m_bUseMask = TRUE;
  127. m_strMask = m_bHasSecond ? lpszTime1Mask : lpszTime2Mask;
  128. m_strLiteral = m_bHasSecond ? lpszTime1Literal : lpszTime2Literal;
  129. }
  130. IMPLEMENT_DYNAMIC(CTimeEdit, CDateEdit)
  131. CString CTimeEdit::TimeToString(COleDateTime dt, BOOL bHasSecond /* = FALSE */ )
  132. {
  133. // 如果输入的COleDateTime对象不合法,则使用缺省构造函数产生的时间
  134. LPCTSTR lpsz = bHasSecond ? lpszTime1Format : lpszTime2Format;
  135. if (dt.GetStatus() == COleDateTime::valid)
  136. return dt.Format(lpsz);
  137. else
  138. return COleDateTime().Format(lpsz);
  139. }
  140. void CTimeEdit::SetDateTime(COleDateTime dt)
  141. {
  142. m_strWindowText = TimeToString(dt, m_bHasSecond);
  143. SetWindowText(m_strWindowText);
  144. }
  145. BOOL CTimeEdit::ProcessMask(UINT& nChar,int nEndPos)
  146. {
  147. // check the key against the mask
  148. switch ( m_strMask.GetAt( nEndPos ) )
  149. {
  150. case '0': // digit only //completely changed this
  151. {
  152. if ( _istdigit( (TCHAR)nChar ) )
  153. {
  154. switch (nEndPos)
  155. {
  156. case 0: // 小时的十位
  157. if (nChar > '2')
  158. {
  159. return FALSE;
  160. }
  161. break;
  162. case 1: // 小时的个位
  163. if (m_strWindowText.GetAt(0) == '2' && nChar > '3')
  164. {
  165. return FALSE;
  166. }
  167. break;
  168. case 3: // 分钟的十位
  169. if (nChar > '5')
  170. {
  171. return FALSE;
  172. }
  173. break;
  174. case 4: // 分钟的个位
  175. if (nChar > '9')
  176. {
  177. return FALSE;
  178. }
  179. break;
  180. case 6: // 秒的十位
  181. if (nChar > '5')
  182. {
  183. return FALSE;
  184. }
  185. break;
  186. case 7: // 秒的个位
  187. if (nChar > '9')
  188. {
  189. return FALSE;
  190. }
  191. break;
  192. }
  193. return TRUE;
  194. }
  195. break;
  196. }
  197. }
  198. return FALSE;
  199. }
  200. /////////////////////////////////////////////////////////////////////////////
  201. // 类 CDegreeEdit
  202. /////////////////////////////////////////////////////////////////////////////
  203. CDegreeEdit::CDegreeEdit(int nSecondPrecision /* = 2 */)
  204. {
  205. // 确保秒的小数部分的位数在有效范围之内
  206. const int nMinPrecision = 0; // 最小有效位数
  207. const int nMaxPrecision = 3; // 最大有效位数
  208. ASSERT(nSecondPrecision >= nMinPrecision && nSecondPrecision <= nMaxPrecision);
  209. m_nSecondPrecision = nSecondPrecision;
  210. if (m_nSecondPrecision < nMinPrecision)
  211. {
  212. m_nSecondPrecision = nMinPrecision;
  213. }
  214. else if (m_nSecondPrecision > nMaxPrecision)
  215. {
  216. m_nSecondPrecision = nMaxPrecision;
  217. }
  218. m_chPrompt = _T(' '); // 使用空格做提示字符
  219. if (m_nSecondPrecision == 0)
  220. {
  221. m_strMask = _T("#000°00'00\"");
  222. m_strLiteral = _T(" ° ' \"");
  223. }
  224. else
  225. {
  226. m_strMask = _T("#000°00'00.") + CString(_T('0'), m_nSecondPrecision) + _T('\"');
  227. m_strLiteral = _T(" ° ' .") + CString(_T(' '), m_nSecondPrecision) + _T('\"');
  228. }
  229. }
  230. IMPLEMENT_DYNAMIC(CDegreeEdit, CMaskEdit)
  231. void CDegreeEdit::SetDegree(double fDegree)
  232. {
  233. // 以度分秒的格式显示度
  234. m_strWindowText = CDegreeEdit::DegreeToString(fDegree, m_nSecondPrecision);
  235. SetWindowText( m_strWindowText );
  236. }
  237. double CDegreeEdit::GetDegree()
  238. {
  239. CString strText;
  240. GetWindowText(strText);
  241. // 读取数据
  242. double fDegree = CDegreeEdit::StringToDegree(strText);
  243. SetDegree(fDegree);
  244. return fDegree;
  245. }
  246. CString CDegreeEdit::DegreeToString(double fDegree, int nSecondPrecision /* = 2 */)
  247. {
  248. // 计算度分秒
  249. int degree, minute;
  250. double second;
  251. double temp = fabs(fDegree)+(1E-6/3600);// 由于浮点数存在舍入误差,可能给取整计算度和分
  252. degree = (int)temp; // 带来问题。例如10.7表示为 double 类型时,其值
  253. temp = (temp-degree) * 60; // 为10.699...99,取整得到的度等于10,分等于41,
  254. minute = (int)temp; // 秒用格式%05.2f输出得到60.00。这显然不合理。
  255. second = (temp-minute) * 60; // 如果加一个很小的数,既能解决这个问题,又不会
  256. // 影响数值的精确度。这里加的是百万分之一秒。
  257. // 生成度分秒格式的文本
  258. CString strFormat; // 格式字符串
  259. CString strMaxSecond; // 秒的最大值(文本格式)
  260. if (nSecondPrecision == 0)
  261. {
  262. strFormat = _T("%3d°%02d'%02.0f\"");
  263. strMaxSecond = _T("59");
  264. }
  265. else
  266. {
  267. strFormat.Format( _T("%%3d°%%02d'%%0%d.%df\""), 3+nSecondPrecision, nSecondPrecision);
  268. strMaxSecond = _T("59.") + CString(_T('9'), nSecondPrecision);
  269. }
  270. #ifdef _UNICODE
  271. char ansi_buf[256];
  272. ::WideCharToMultiByte(CP_ACP, 0, strMaxSecond, -1, ansi_buf, 256, NULL, NULL);
  273. double fMaxSecond = atof(ansi_buf); // 秒的最大值(浮点数格式)
  274. #else
  275. double fMaxSecond = atof(strMaxSecond); // 秒的最大值(浮点数格式)
  276. #endif
  277. CString strText;
  278. strText.Format( strFormat,
  279. min(999,degree), // 不超出999
  280. minute,
  281. min(fMaxSecond,second) ); // 避免出现类似59.999"被格式化输出成60.00"的情况
  282. if (fDegree >= 0)
  283. strText = _T(' ') + strText;
  284. else
  285. strText = _T('-') + strText;
  286. return strText;
  287. }
  288. double CDegreeEdit::StringToDegree(CString strText)
  289. {
  290. // 删除文本中的提示字符
  291. CString strPromptChar( _T(' ') );
  292. strText.Replace(strPromptChar, NULL);
  293. // 读取数据
  294. int degree = 0, minute = 0;
  295. float second = 0;
  296. #ifdef _UNICODE
  297. char ansi_buf[256];
  298. ::WideCharToMultiByte(CP_ACP, 0, strText, -1, ansi_buf, 256, NULL, NULL);
  299. sscanf(ansi_buf, "%d°%d'%f", &degree, &minute, &second);
  300. #else
  301. sscanf(strText, "%d°%d'%f", &degree, &minute, &second);
  302. #endif
  303. double fDegree = abs(degree) + minute/60.0 + second/3600.0;
  304. fDegree = min(999, fDegree); // 不超出999
  305. if (strText.Find( _T('-') ) >= 0)
  306. fDegree = -fDegree;
  307. return fDegree;
  308. }
  309. /////////////////////////////////////////////////////////////////////////////
  310. // DDX_ routines
  311. /////////////////////////////////////////////////////////////////////////////
  312. void AFXAPI DDX_OleDateTime(CDataExchange* pDX, int nIDC, COleDateTime& rDateTime)
  313. {
  314. // 从控件ID获取CDateEdit对象指针
  315. HWND hControl = ::GetDlgItem(pDX->m_pDlgWnd->m_hWnd, nIDC);
  316. CWnd* pControl = CWnd::FromHandlePermanent(hControl);
  317. ASSERT(pControl);
  318. ASSERT(pControl->IsKindOf(RUNTIME_CLASS(CDateEdit)));
  319. CDateEdit* pDateEdit = (CDateEdit*)pControl;
  320. // 进行数据交换
  321. if ( pDX->m_bSaveAndValidate )
  322. {
  323. COleDateTime dt = pDateEdit->GetDateTime( );
  324. if (dt.GetStatus() != COleDateTime::valid)
  325. {
  326. if (pDateEdit->IsKindOf(RUNTIME_CLASS(CTimeEdit)))
  327. // 时间编辑控件
  328. AfxMessageBox( _T("请键入一个合法的时间。") );
  329. else
  330. // 日期编辑控件
  331. AfxMessageBox( _T("请键入一个合法的日期。") );
  332. pDX->PrepareCtrl(nIDC);
  333. pDX->Fail(); // 该函数把输入焦点传给控件,然后抛出一个异常
  334. }
  335. rDateTime = dt;
  336. }
  337. else
  338. {
  339. pDateEdit->SetDateTime( rDateTime );
  340. }
  341. }
  342. void AFXAPI DDX_Degree(CDataExchange* pDX, int nIDC, double& value)
  343. {
  344. // 从控件ID获取CDegreeEdit对象指针
  345. HWND hControl = ::GetDlgItem(pDX->m_pDlgWnd->m_hWnd, nIDC);
  346. CWnd* pControl = CWnd::FromHandlePermanent(hControl);
  347. ASSERT(pControl);
  348. ASSERT(pControl->IsKindOf(RUNTIME_CLASS(CDegreeEdit)));
  349. CDegreeEdit* pDegreeEdit = (CDegreeEdit*)pControl;
  350. // 进行数据交换
  351. if ( pDX->m_bSaveAndValidate )
  352. {
  353. value = pDegreeEdit->GetDegree();
  354. }
  355. else
  356. {
  357. pDegreeEdit->SetDegree( value );
  358. }
  359. }