📄 amsedit.cpp
字号:
if (IsValidDayDigit(c, 0) && _ShouldEnter(c))
{
if (nLen > nStart)
{
m_pEdit->SetSel(nStart, nStart + 1);
m_pEdit->ReplaceSel(CString(c), TRUE);
if (nLen > nStart + 1)
{
if (!IsValidDay(GetDay()))
{
m_pEdit->SetSel(nStart + 1, nStart + 2);
m_pEdit->ReplaceSel(CString(GetMinDayDigit(1)), TRUE);
m_pEdit->SetSel(nStart + 1, nStart + 2);
}
}
}
else
Behavior::_OnChar(uChar, nRepCnt, nFlags);
}
// Check if we can insert the digit with a leading zero
else if (nLen == nStart && GetMinDayDigit(0) == '0' && IsValidDayDigit(c, 1) && _ShouldEnter(c))
{
m_pEdit->SetSel(nStart, nStart + 2);
m_pEdit->ReplaceSel(CString('0') + c, TRUE);
}
}
break;
}
case 4: // FOURTH DIGIT
{
if (m_uFlags & DayBeforeMonth)
{
if (IsValidMonthDigit(c, 1) && _ShouldEnter(c))
{
if (nLen > nStart)
{
m_pEdit->SetSel(nStart, nStart + 1);
m_pEdit->ReplaceSel(CString(c), TRUE);
if (GetDay() > 0 && AdjustMaxDay())
m_pEdit->SetSel(GetDayStartPosition(), GetDayStartPosition() + 2);
}
else
{
Behavior::_OnChar(uChar, nRepCnt, nFlags);
AdjustMaxDay();
}
}
// Check if it's a slash and the first digit (preceded by a zero) is a valid month
else if (c == m_cSep && nLen == nStart && GetMinMonthDigit(0) == '0' && IsValidMonth(_ttoi(CString('0') + strText[3])) && _ShouldEnter(c))
{
m_pEdit->SetSel(3, nStart);
m_pEdit->ReplaceSel(CString('0') + strText[3] + c, TRUE);
}
}
else
{
if (IsValidDayDigit(c, 1) && _ShouldEnter(c))
{
if (nLen > nStart)
{
m_pEdit->SetSel(nStart, nStart + 1);
m_pEdit->ReplaceSel(CString(c), TRUE);
}
else
Behavior::_OnChar(uChar, nRepCnt, nFlags);
}
// Check if it's a slash and the first digit (preceded by a zero) is a valid month
else if (c == m_cSep && nLen == nStart && GetMinDayDigit(0) == '0' && IsValidDay(_ttoi(CString('0') + strText[3])) && _ShouldEnter(c))
{
m_pEdit->SetSel(3, nStart);
m_pEdit->ReplaceSel(CString('0') + strText[3] + c, TRUE);
}
}
break;
}
case 5: // SECOND SLASH (year's first digit)
{
int nSlash = 0;
if (c == m_cSep)
nSlash = 1;
else
nSlash = (IsValidYearDigit(c, 0) ? 2 : 0);
// If we need the slash, enter it
if (nSlash && _ShouldEnter(c))
{
m_pEdit->SetSel(nStart, nStart + 1, FALSE);
m_pEdit->ReplaceSel(CString(m_cSep), TRUE);
}
// If the slash is to be preceded by a valid digit, "type" it in.
if (nSlash == 2)
keybd_event((BYTE)c, 0, 0, 0);
break;
}
case 6: // YEAR (all 4 digits)
case 7:
case 8:
case 9:
{
if (IsValidYearDigit(c, nStart - GetYearStartPosition()) && _ShouldEnter(c))
{
if (nLen > nStart)
{
m_pEdit->SetSel(nStart, nStart + 1, FALSE);
m_pEdit->ReplaceSel(CString(c), TRUE);
for (; nStart + 1 < nLen && nStart < 9; nStart++)
{
if (!IsValidYearDigit(strText[nStart + 1], nStart - (GetYearStartPosition() - 1)))
{
m_pEdit->SetSel(nStart + 1, 10, FALSE);
CString strPortion;
for (int iPos = nStart + 1; iPos < nLen && iPos < 10; iPos++)
strPortion += GetMinYearDigit(iPos - GetYearStartPosition(), false);
m_pEdit->ReplaceSel(strPortion, TRUE);
m_pEdit->SetSel(nStart + 1, 10, FALSE);
break;
}
}
}
else
Behavior::_OnChar(uChar, nRepCnt, nFlags);
if (IsValidYear(GetYear()))
{
AdjustMaxDay(); // adjust the day first
AdjustMaxMonthAndDay(); // then adjust the month and the day, if necessary
}
}
break;
}
}
}
// Handles the WM_KEYDOWN message, which is called when the user enters a special character such as Delete or the arrow keys.
void CAMSEdit::DateBehavior::_OnKeyDown(UINT uChar, UINT nRepCnt, UINT nFlags)
{
// Check to see if it's read only
if (m_pEdit->IsReadOnly())
return;
switch (uChar)
{
case VK_DELETE:
{
// If deleting make sure it's the last character or that
// the selection goes all the way to the end of the text
int nStart, nEnd;
m_pEdit->GetSel(nStart, nEnd);
CString strText = m_pEdit->GetText();
int nLen = strText.GetLength();
if (nEnd != nLen)
{
if (!(nEnd == nStart && nEnd == nLen - 1))
return;
}
break;
}
case VK_UP:
{
// If pressing the UP arrow, increment the corresponding value.
int nStart, nEnd;
m_pEdit->GetSel(nStart, nEnd);
if (nStart >= GetYearStartPosition() && nStart <= GetYearStartPosition() + 4)
{
int nYear = GetYear();
if (nYear >= m_dateMin.GetYear() && nYear < m_dateMax.GetYear())
SetYear(++nYear);
}
else if (nStart >= GetMonthStartPosition() && nStart <= GetMonthStartPosition() + 2)
{
int nMonth = GetMonth();
if (nMonth >= GetMinMonth() && nMonth < GetMaxMonth())
SetMonth(++nMonth);
}
else if (nStart >= GetDayStartPosition() && nStart <= GetDayStartPosition() + 2)
{
int nDay = GetDay();
if (nDay >= GetMinDay() && nDay < GetMaxDay())
SetDay(++nDay);
}
return;
}
case VK_DOWN:
{
// If pressing the DOWN arrow, decrement the corresponding value.
int nStart, nEnd;
m_pEdit->GetSel(nStart, nEnd);
if (nStart >= GetYearStartPosition() && nStart <= GetYearStartPosition() + 4)
{
int nYear = GetYear();
if (nYear > m_dateMin.GetYear())
SetYear(--nYear);
}
else if (nStart >= GetMonthStartPosition() && nStart <= GetMonthStartPosition() + 2)
{
int nMonth = GetMonth();
if (nMonth > GetMinMonth())
SetMonth(--nMonth);
}
else if (nStart >= GetDayStartPosition() && nStart <= GetDayStartPosition() + 2)
{
int nDay = GetDay();
if (nDay > GetMinDay())
SetDay(--nDay);
}
return;
}
}
Behavior::_OnKeyDown(uChar, nRepCnt, nFlags);
}
// Handles the WM_KILLFOCUS message, which is called when the user leaves the control.
// It's used here to check if any action needs to be taken based on the control's value.
void CAMSEdit::DateBehavior::_OnKillFocus(CWnd* pNewWnd)
{
Behavior::_OnKillFocus(pNewWnd);
// Check if any of the OnKillFocus flags is set
if (!(m_uFlags & OnKillFocus_Max))
return;
CString strText = m_pEdit->GetText();
// If it's empty, take action based on the flag
if (strText.IsEmpty())
{
if (m_uFlags & OnKillFocus_Beep_IfEmpty)
MessageBeep(MB_ICONEXCLAMATION);
if (m_uFlags & OnKillFocus_SetValid_IfEmpty)
m_pEdit->SetWindowText(_T(" "));
if ((m_uFlags & OnKillFocus_ShowMessage_IfEmpty) == OnKillFocus_ShowMessage_IfEmpty)
ShowErrorMessage();
if (m_uFlags & OnKillFocus_SetFocus_IfEmpty)
m_pEdit->SetFocus();
return;
}
if (!IsValid())
{
if (m_uFlags & OnKillFocus_Beep_IfInvalid)
MessageBeep(MB_ICONEXCLAMATION);
if (m_uFlags & OnKillFocus_SetValid_IfInvalid)
_Redraw();
if ((m_uFlags & OnKillFocus_ShowMessage_IfInvalid) == OnKillFocus_ShowMessage_IfInvalid)
ShowErrorMessage();
if (m_uFlags & OnKillFocus_SetFocus_IfInvalid)
m_pEdit->SetFocus();
}
}
// Returns the given value as a string with or without leading zeros.
CString CAMSEdit::DateBehavior::GetString(int nValue, bool bTwoDigitWithLeadingZero /*= true*/)
{
CString strValue;
if (bTwoDigitWithLeadingZero)
strValue.Format(_T("%02d"), nValue);
else
strValue.Format(_T("%d"), nValue);
return strValue;
}
// Returns the zero-based position of the month inside the control.
// This is based on whether the month is shown before or after the day.
int CAMSEdit::DateBehavior::GetMonthStartPosition() const
{
return ((m_uFlags & DayBeforeMonth) ? 3 : 0);
}
// Returns the zero-based position of the day inside the control.
// This is based on whether the day is shown before or after the month.
int CAMSEdit::DateBehavior::GetDayStartPosition() const
{
return ((m_uFlags & DayBeforeMonth) ? 0 : 3);
}
// Returns the zero-based position of the year inside the control.
int CAMSEdit::DateBehavior::GetYearStartPosition() const
{
return 6;
}
// Returns the maximum value for the month based on the allowed range.
int CAMSEdit::DateBehavior::GetMaxMonth() const
{
if (GetValidYear() == m_dateMax.GetYear())
return m_dateMax.GetMonth();
return 12;
}
// Returns the minimum value for the month based on the allowed range.
int CAMSEdit::DateBehavior::GetMinMonth() const
{
if (GetValidYear() == m_dateMin.GetYear())
return m_dateMin.GetMonth();
return 1;
}
// Returns the maximum value for the day based on the allowed range.
int CAMSEdit::DateBehavior::GetMaxDay() const
{
int nYear = GetValidYear();
int nMonth = GetValidMonth();
if (nYear == m_dateMax.GetYear() && nMonth == m_dateMax.GetMonth())
return m_dateMax.GetDay();
return GetMaxDayOfMonth(nMonth, nYear);
}
// Returns the minimum value for the day based on the allowed range.
int CAMSEdit::DateBehavior::GetMinDay() const
{
int nYear = GetValidYear();
int nMonth = GetValidMonth();
if (nYear == m_dateMin.GetYear() && nMonth == m_dateMin.GetMonth())
return m_dateMin.GetDay();
return 1;
}
// Returns the maximum value for the day based on the given month and year.
int CAMSEdit::DateBehavior::GetMaxDayOfMonth(int nMonth, int nYear)
{
ASSERT(nMonth >= 1 && nMonth <= 12);
switch (nMonth)
{
case 4:
case 6:
case 9:
case 11:
return 30;
case 2:
return IsLeapYear(nYear) ? 29 : 28;
}
return 31;
}
// Returns the digit at the given position (0 or 1) for the maximum value of the month allowed.
TCHAR CAMSEdit::DateBehavior::GetMaxMonthDigit(int nPos) const
{
ASSERT(nPos >= 0 && nPos <= 1);
int nYear = GetValidYear();
int nMaxMonth = m_dateMax.GetMonth();
int nMaxYear = m_dateMax.GetYear();
// First digit
if (nPos == 0)
{
// If the year is at the max, then use the first digit of the max month
if (nYear == nMaxYear)
return GetString(nMaxMonth)[0];
// Otherwise, it's always '1'
return '1';
}
// Second digit
CString strText = m_pEdit->GetText();
TCHAR cFirstDigit = (strText.GetLength() > GetMonthStartPosition()) ? strText[GetMonthStartPosition()] : '0';
ASSERT(cFirstDigit); // must have a valid first digit at this point
// If the year is at the max, then check if the first digits match
if (nYear == nMaxYear && (IsValidYear(GetYear()) || nMaxYear == m_dateMin.GetYear()))
{
// If the first digits match, then use the second digit of the max month
if (GetString(nMaxMonth)[0] == cFirstDigit)
return GetString(nMaxMonth)[1];
// Assuming the logic for the first digit is correct, then it must be '0'
ASSERT(cFirstDigit == '0');
return '9';
}
// Use the first digit to determine the second digit's max
return (cFirstDigit == '1' ? '2' : '9');
}
// Returns the digit at the given position (0 or 1) for the minimum value of the month allowed.
TCHAR CAMSEdit::DateBehavior::GetMinMonthDigit(int nPos) const
{
ASSERT(nPos >= 0 && nPos <= 1);
int nYear = GetValidYear();
int nMinMonth = m_dateMin.GetMonth();
int nMinYear = m_dateMin.GetYear();
// First digit
if (nPos == 0)
{
// If the year is at the min, then use the first digit of the min month
if (nYear == nMinYear)
return GetString(nMinMonth)[0];
// Otherwise, it's always '0'
return '0';
}
// Second digit
CString strText = m_pEdit->GetText();
TCHAR cFirstDigit = (strText.GetLength() > GetMonthStartPosition()) ? strText[GetMonthStartPosition()] : '0';
if (!cFirstDigit)
return '1';
// If the year is at the max, then check if the first digits match
if (nYear == nMinYear && (IsValidYear(GetYear()) || nMinYear == m_dateMax.GetYear()))
{
// If the first digits match, then use the second digit of the max month
if (GetString(nMinMonth)[0] == cFirstDigit)
return GetString(nMinMonth)[1];
return '0';
}
// Use the first digit to determine the second digit's min
return (cFirstDigit == '1' ? '0' : '1');
}
// Returns true if the digit at the given position (0 or 1) is within the allowed range for the month.
bool CAMSEdit::DateBehavior::IsValidMonthDigit(TCHAR c, int nPos) const
{
return (c >= GetMinMonthDigit(nPos) && c <= GetMaxMonthDigit(nPos));
}
// Returns true if the given month is valid and falls within the range.
bool CAMSEdit::DateBehavior::IsValidMonth(int nMonth) const
{
int nYear = GetValidYear();
int nDay = GetValidDay();
return IsWithinRange(COleDateTime(nYear, nMonth, nDay, 0, 0, 0));
}
// Returns the digit at the given position (0 or 1) for the maximum value of the day allowed.
TCHAR CAMSEdit::DateBehavior::GetMaxDayDigit(int nPos) const
{
ASSERT(nPos >= 0 && nPos <= 1);
int nMonth = GetValidMonth();
int nYear = GetValidYear();
int nMaxDay = m_dateMax.GetDay();
int nMaxMonth = m_dateMa
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -