📄 amsedit.cpp
字号:
if (nDecimalPos >= 0)
strNewText = strNewText.Left(nDecimalPos);
if (m_nDigitsInGroup > 0)
{
int nLen = strNewText.GetLength();
BOOL bIsNegative = (!strNewText.IsEmpty() && strNewText[0] == m_cNegativeSign);
// Loop in reverse and stick the separator every m_nDigitsInGroup digits.
for (int iPos = nLen - (m_nDigitsInGroup + 1); iPos >= bIsNegative; iPos -= m_nDigitsInGroup)
strNewText = strNewText.Left(iPos + 1) + m_cGroupSeparator + strNewText.Mid(iPos + 1);
}
// Prepend the prefix, if the number is not empty.
if (!strNewText.IsEmpty() || nDecimalPos >= 0)
{
strNewText = m_strPrefix + strNewText;
if (nDecimalPos >= 0)
strNewText += strNumericText.Mid(nDecimalPos);
}
return strNewText;
}
CString CAMSEdit::NumericBehavior::_GetValidText() const
{
CString strText = m_pEdit->GetText();
CString strNewText;
BOOL bIsNegative = FALSE;
int nPrefixLen = m_strPrefix.GetLength();
// Remove any invalid characters from the number
for (int iPos = 0, nDecimalPos = -1, nNewLen = 0, nLen = strText.GetLength();
iPos < nLen; iPos++)
{
TCHAR c = strText[iPos];
// Check for a negative sign
if (iPos == nPrefixLen && c == m_cNegativeSign && m_bAllowNegative)
{
strNewText += c;
nNewLen++;
bIsNegative = TRUE;
}
// Check for a digit
else if (_istdigit(c))
{
// Make sure it doesn't go beyond the limits
if (nDecimalPos < 0 && nNewLen == m_nMaxWholeDigits + bIsNegative)
continue;
if (nDecimalPos >= 0 && nNewLen > nDecimalPos + m_nMaxDecimalPlaces)
break;
strNewText += c;
nNewLen++;
}
// Check for a decimal point
else if (c == m_cDecimalPoint && nDecimalPos < 0)
{
if (m_nMaxDecimalPlaces == 0)
break;
strNewText += c;
nDecimalPos = nNewLen;
nNewLen++;
}
}
return GetSeparatedText(strNewText);
}
void CAMSEdit::NumericBehavior::_OnChar(UINT uChar, UINT nRepCnt, UINT nFlags)
{
TCHAR c = (TCHAR)uChar;
int nStart, nEnd;
m_pEdit->GetSel(nStart, nEnd);
CString strText = m_pEdit->GetText();
CString strNumericText = GetNumericText(strText);
int nDecimalPos = strText.Find(m_cDecimalPoint);
int nNumericDecimalPos = strNumericText.Find(m_cDecimalPoint);
int nLen = strText.GetLength();
int nNumericLen = strNumericText.GetLength();
int nPrefixLen = m_strPrefix.GetLength();
int nSepCount = GetGroupSeparatorCount(strText);
bool bNeedAdjustment = false;
// Check if we're in the prefix's location
if (nStart < nPrefixLen && c != VK_BACK)
{
TCHAR cPrefix = m_strPrefix[nStart];
// Check if it's the same character as the prefix.
if (cPrefix == c && _ShouldEnter(c))
{
if (nLen > nStart)
{
m_pEdit->SetSel(nStart, nStart + 1);
m_pEdit->ReplaceSel(CString(c), TRUE);
}
else
Behavior::_OnChar(uChar, nRepCnt, nFlags);
}
// If it's a part of the number, enter the prefix
else if ((_istdigit(c) || c == m_cNegativeSign || c == m_cDecimalPoint) && _ShouldEnter(c))
{
m_pEdit->SetSel(nStart, nPrefixLen);
m_pEdit->ReplaceSel(m_strPrefix.Mid(nStart), TRUE);
Behavior::_OnChar(uChar, nRepCnt, nFlags);
}
return;
}
// Check if it's a negative sign
if (c == m_cNegativeSign && m_bAllowNegative)
{
// If it's at the beginning, determine if it should overwritten
if (nStart == nPrefixLen)
{
if (!strNumericText.IsEmpty() && strNumericText[0] == m_cNegativeSign && _ShouldEnter(c))
{
m_pEdit->SetSel(nStart, nStart + 1);
m_pEdit->ReplaceSel(CString(m_cNegativeSign), TRUE);
return;
}
}
// If we're not at the beginning, toggle the sign
else if (_ShouldEnter(c))
{
if (strNumericText[0] == m_cNegativeSign)
{
m_pEdit->SetSel(nPrefixLen, nPrefixLen + 1);
m_pEdit->ReplaceSel(_T(""), TRUE);
m_pEdit->SetSel(nStart - 1, nEnd - 1);
}
else
{
m_pEdit->SetSel(nPrefixLen, nPrefixLen);
m_pEdit->ReplaceSel(CString(m_cNegativeSign), TRUE);
m_pEdit->SetSel(nStart + 1, nEnd + 1);
}
return;
}
}
// Check if it's a decimal point (only one is allowed).
else if (c == m_cDecimalPoint && m_nMaxDecimalPlaces > 0)
{
if (nDecimalPos >= 0)
{
if (_ShouldEnter(c))
m_pEdit->SetSel(nDecimalPos + 1, nDecimalPos + 1);
return;
}
}
// Check if it's a digit
else if (_istdigit(c))
{
// Check if we're on the right of the decimal point.
if (nDecimalPos >= 0 && nDecimalPos < nStart)
{
if (strNumericText.Mid(nNumericDecimalPos + 1).GetLength() == m_nMaxDecimalPlaces)
{
if (nStart <= nDecimalPos + m_nMaxDecimalPlaces && _ShouldEnter(c))
{
m_pEdit->SetSel(nStart, nStart + 1);
m_pEdit->ReplaceSel(CString(c), TRUE);
}
return;
}
}
// We're on the left side of the decimal point
else
{
BOOL bIsNegative = (!strNumericText.IsEmpty() && strNumericText[0] == m_cNegativeSign);
// Make sure we can still enter digits.
if (nStart == m_nMaxWholeDigits + bIsNegative + nSepCount + nPrefixLen)
return;
if (strNumericText.Mid(0, nNumericDecimalPos >= 0 ? nNumericDecimalPos : nNumericLen).GetLength() == m_nMaxWholeDigits + bIsNegative)
{
if (_ShouldEnter(c))
{
if (strText[nStart] == m_cGroupSeparator)
nStart++;
m_pEdit->SetSel(nStart, nStart + 1);
m_pEdit->ReplaceSel(CString(c), TRUE);
}
return;
}
bNeedAdjustment = true;
}
}
// Check if it's a non-printable character, such as Backspace or Ctrl+C
else if (!_istprint(c))
bNeedAdjustment = true;
else
return;
// Check if the character should be entered
if (!_ShouldEnter(c))
return;
Behavior::_OnChar(uChar, nRepCnt, nFlags);
// If the decimal point was added/removed or a separator needs adding/removing, adjust the text
if (bNeedAdjustment || nNumericDecimalPos != GetNumericText(m_pEdit->GetText()).Find(m_cDecimalPoint))
AdjustSeparators(nSepCount);
}
void CAMSEdit::NumericBehavior::_OnKeyDown(UINT uChar, UINT nRepCnt, UINT nFlags)
{
switch (uChar)
{
case VK_DELETE:
{
int nStart, nEnd;
m_pEdit->GetSel(nStart, nEnd);
CString strText = m_pEdit->GetText();
int nLen = strText.GetLength();
// If deleting the prefix, don't allow it if there's a number after it.
int nPrefixLen = m_strPrefix.GetLength();
if (nStart < nPrefixLen && nLen > nPrefixLen)
{
if (nEnd == nLen)
break;
return;
}
// Allow the deletion and then adjust the value
int nSepCount = GetGroupSeparatorCount(strText);
Behavior::_OnKeyDown(uChar, nRepCnt, nFlags);
AdjustSeparators(nSepCount);
// If everything on the right was deleted, put the selection on the right
if (nEnd == nLen)
m_pEdit->SetSel(nStart, nStart);
return;
}
}
Behavior::_OnKeyDown(uChar, nRepCnt, nFlags);
}
/////////////////////////////////////////////////////////////////////////////
// CAMSEdit::DateBehavior
#define AMS_MIN_CTIME CTime(1970, 1, 1, 0, 0, 0)
#define AMS_MAX_CTIME CTime(2037, 12, 31, 23, 59, 59)
#define AMS_MIN_OLEDATETIME COleDateTime(1900, 1, 1, 0, 0, 0)
#define AMS_MAX_OLEDATETIME COleDateTime(9999, 12, 31, 23, 59, 59)
#define AMS_DATE_SEP '/'
#define AMS_DATE_SEP_STR _T("/")
CAMSEdit::DateBehavior::DateBehavior(CAMSEdit* pEdit) :
Behavior(pEdit),
m_dateCurrent(COleDateTime::GetCurrentTime()),
m_dateMin(AMS_MIN_OLEDATETIME),
m_dateMax(AMS_MAX_OLEDATETIME),
m_cSep(AMS_DATE_SEP),
m_uFlags(None)
{
// Get the system's date separator
if (::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, &m_cSep, 0))
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDATE, &m_cSep, sizeof(m_cSep));
// Determine if the day should go before the month
TCHAR szShortDate[MAX_PATH];
if (::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, szShortDate, 0))
{
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, szShortDate, sizeof(szShortDate));
for (int iPos = 0; szShortDate[iPos]; iPos++)
{
TCHAR c = _totupper(szShortDate[iPos]);
if (c == 'M') // see if the month is first
break;
if (c == 'D') // see if the day is first, and then set the flag
{
m_uFlags |= DayBeforeMonth;
break;
}
}
}
m_uFlags |= DayBeforeMonth; //设置DD-MM-YYYY
}
void CAMSEdit::DateBehavior::_OnChar(UINT uChar, UINT nRepCnt, UINT nFlags)
{
TCHAR c = (TCHAR)uChar;
int nDigit = _ttoi(CString(c));
int nStart, nEnd;
m_pEdit->GetSel(nStart, nEnd);
CString strText = m_pEdit->GetText();
int nLen = strText.GetLength();
// Check for a non-printable character (such as Ctrl+C)
if (!_istprint(c))
{
if (c == VK_BACK && nStart != nLen)
{
m_pEdit->SendMessage(WM_KEYDOWN, VK_LEFT); // move the cursor left
return;
}
// Allow backspace only if the cursor is all the way to the right
if (_ShouldEnter(c))
Behavior::_OnChar(uChar, nRepCnt, nFlags);
return;
}
// Add the digit depending on its location
switch (nStart)
{
case 0: // FIRST DIGIT
{
if (m_uFlags & DayBeforeMonth)
{
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);
}
}
else
{
if (IsValidMonthDigit(c, 0) && _ShouldEnter(c))
{
if (nLen > nStart)
{
m_pEdit->SetSel(nStart, nStart + 1);
m_pEdit->ReplaceSel(CString(c), TRUE);
if (nLen > nStart + 1)
{
if (!IsValidMonth(GetMonth()))
{
m_pEdit->SetSel(nStart + 1, nStart + 2);
m_pEdit->ReplaceSel(CString(GetMinMonthDigit(1)), TRUE);
m_pEdit->SetSel(nStart + 1, nStart + 2);
}
}
AdjustMaxDay();
}
else
Behavior::_OnChar(uChar, nRepCnt, nFlags);
}
}
break;
}
case 1: // SECOND DIGIT
{
if (m_uFlags & DayBeforeMonth)
{
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);
}
}
else
{
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);
}
}
break;
}
case 2: // FIRST SLASH
{
int nSlash = 0;
if (c == m_cSep)
nSlash = 1;
else
{
if (m_uFlags & DayBeforeMonth)
nSlash = (IsValidMonthDigit(c, 0) ? 2 : 0);
else
nSlash = (IsValidDayDigit(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 3: // THIRD DIGIT
{
if (m_uFlags & DayBeforeMonth)
{
if (IsValidMonthDigit(c, 0) && _ShouldEnter(c))
{
if (nLen > nStart)
{
m_pEdit->SetSel(nStart, nStart + 1);
m_pEdit->ReplaceSel(CString(c), TRUE);
if (nLen > nStart + 1)
{
if (!IsValidMonth(GetMonth()))
{
m_pEdit->SetSel(nStart + 1, nStart + 2);
m_pEdit->ReplaceSel(CString(GetMinMonthDigit(1)), TRUE);
m_pEdit->SetSel(nStart + 1, nStart + 2);
}
}
AdjustMaxDay();
}
else
Behavior::_OnChar(uChar, nRepCnt, nFlags);
}
}
else
{
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);
}
}
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);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -