📄 amsedit.cpp
字号:
*pcDecimal = m_cDecimalPoint;
if (pcGroup)
*pcGroup = m_cGroupSeparator;
}
// Sets the text to be automatically inserted in front of the number (such as a currency sign).
void CAMSEdit::NumericBehavior::SetPrefix(const CString& strPrefix)
{
if (m_strPrefix == strPrefix)
return;
m_strPrefix = strPrefix;
_Redraw();
}
// Returns the text to be automatically inserted in front of the number (such as a currency sign).
const CString& CAMSEdit::NumericBehavior::GetPrefix() const
{
return m_strPrefix;
}
// Parses the given strMask to set the control's configuration.
void CAMSEdit::NumericBehavior::SetMask(const CString& strMask)
{
int nDecimalPos = -1;
int nLen = strMask.GetLength();
m_nMaxWholeDigits = 0;
m_nMaxDecimalPlaces = 0;
m_nDigitsInGroup = 0;
m_uFlags = (m_uFlags & ~CannotBeNegative); // allow it to be negative
m_strPrefix = _T("");
for (int iPos = nLen - 1; iPos >= 0; iPos--)
{
TCHAR c = strMask[iPos];
if (c == '#')
{
if (nDecimalPos >= 0)
m_nMaxWholeDigits++;
else
m_nMaxDecimalPlaces++;
}
else if ((c == '.' || c == m_cDecimalPoint) && nDecimalPos < 0)
{
nDecimalPos = iPos;
m_cDecimalPoint = c;
}
else if (c == ',' || c == m_cGroupSeparator)
{
if (!m_nDigitsInGroup)
{
m_nDigitsInGroup = (((nDecimalPos >= 0) ? nDecimalPos : nLen) - iPos) - 1;
m_cGroupSeparator = c;
}
}
else
{
m_strPrefix = strMask.Left(iPos + 1);
break;
}
}
if (nDecimalPos < 0)
{
m_nMaxWholeDigits = m_nMaxDecimalPlaces;
m_nMaxDecimalPlaces = 0;
}
ASSERT(m_nMaxWholeDigits > 0); // must have at least one digit on left side of decimal point
_Redraw();
}
// Gets the mask corresponding to the maximum number than can be entered into the control
CString CAMSEdit::NumericBehavior::GetMask() const
{
CString strMask;
for (int iDigit = 0; iDigit < m_nMaxWholeDigits; iDigit++)
strMask += '0';
if (m_nMaxDecimalPlaces)
strMask += m_cDecimalPoint;
for (iDigit = 0; iDigit < m_nMaxDecimalPlaces; iDigit++)
strMask += '0';
strMask = GetSeparatedText(strMask);
for (int iPos = 0, nLen = strMask.GetLength(); iPos < nLen; iPos++)
{
if (strMask[iPos] == '0')
strMask.SetAt(iPos, '#');
}
return strMask;
}
// Sets the range of allowed values to the given minimum and maximum double values.
void CAMSEdit::NumericBehavior::SetRange(double dMin, double dMax)
{
ASSERT(dMin <= dMax);
m_dMin = dMin;
m_dMax = dMax;
_Redraw();
}
// Retrieves the range of allowed values inside the given set of double pointers.
void CAMSEdit::NumericBehavior::GetRange(double* pdMin, double* pdMax) const
{
if (pdMin)
*pdMin = m_dMin;
if (pdMax)
*pdMax = m_dMax;
}
// Returns the number of group separator characters in the given strText.
int CAMSEdit::NumericBehavior::GetGroupSeparatorCount(const CString& strText) const
{
for (int iPos = 0, nSepCount = 0, nLen = strText.GetLength(); iPos < nLen; iPos++)
{
if (strText[iPos] == m_cGroupSeparator)
nSepCount++;
}
return nSepCount;
}
// Returns the given strText as a numeric string.
CString CAMSEdit::NumericBehavior::GetNumericText(const CString& strText, bool bUseMathSymbols /*= false*/) const
{
CString strNewText;
bool bIsNegative = false;
bool bHasDecimalPoint = false;
for (int iPos = 0, nLen = strText.GetLength(); iPos < nLen; iPos++)
{
TCHAR c = strText[iPos];
if (_istdigit(c))
strNewText += c;
else if (c == m_cNegativeSign)
bIsNegative = true;
else if (c == m_cDecimalPoint && !bHasDecimalPoint)
{
bHasDecimalPoint = true;
strNewText += (bUseMathSymbols ? '.' : m_cDecimalPoint);
}
}
// Add the negative sign to the front of the number
if (bIsNegative)
strNewText.Insert(0, bUseMathSymbols ? '-' : m_cNegativeSign);
return strNewText;
}
// Returns the current double as a text value.
// If bTrimTrailingZeros is true, any insignificant zeros after the decimal point are removed.
CString CAMSEdit::NumericBehavior::GetDoubleText(double dText, bool bTrimTrailingZeros /*= true*/) const
{
CString strText;
strText.Format(_T("%lf"), dText);
if (m_cDecimalPoint != '.')
strText.Replace('.', m_cDecimalPoint);
if (bTrimTrailingZeros)
{
strText.TrimRight('0');
strText.TrimRight(m_cDecimalPoint);
}
return strText;
}
// Sets the control's text to the given double value.
// If bTrimTrailingZeros is true, any insignificant zeros after the decimal point are removed.
void CAMSEdit::NumericBehavior::SetDouble(double dText, bool bTrimTrailingZeros /*= true*/)
{
m_pEdit->SetWindowText(GetDoubleText(dText, bTrimTrailingZeros));
}
// Returns the current text as a double value.
double CAMSEdit::NumericBehavior::GetDouble() const
{
return _tcstod(GetNumericText(m_pEdit->GetText()), NULL);
}
// Sets the control's text to the given integer value.
void CAMSEdit::NumericBehavior::SetInt(int nText)
{
CString strText;
strText.Format(_T("%d"), nText);
m_pEdit->SetWindowText(strText);
}
// Returns the current text as an integer value.
int CAMSEdit::NumericBehavior::GetInt() const
{
return _ttoi(GetNumericText(m_pEdit->GetText()));
}
// Adjusts the location of separators based on the nCurrentSeparatorCount.
void CAMSEdit::NumericBehavior::AdjustSeparators(int nCurrentSeparatorCount)
{
SelectionSaver selection = m_pEdit;
m_bAdjustingSeparators = true;
CString strText = _GetValidText();
if (strText != m_pEdit->GetText())
m_pEdit->SetWindowText(strText);
// Adjust the current selection if separators were added/removed
int nNewSeparatorCount = GetGroupSeparatorCount(strText);
if (nCurrentSeparatorCount != nNewSeparatorCount && selection.GetStart() > m_strPrefix.GetLength())
selection += (nNewSeparatorCount - nCurrentSeparatorCount);
m_bAdjustingSeparators = false;
}
// Returns the given text with the group separator characters inserted in the proper places.
CString CAMSEdit::NumericBehavior::GetSeparatedText(const CString& strText) const
{
CString strNumericText = GetNumericText(strText);
CString strNewText = strNumericText;
// Retrieve the number without the decimal point
int nDecimalPos = strNumericText.Find(m_cDecimalPoint);
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;
}
// Inserts nCount zeros into the given string at the given position.
// If nPos is less than 0, the zeros are appended.
void CAMSEdit::NumericBehavior::InsertZeros(CString* pStrText, int nPos, int nCount)
{
ASSERT(pStrText);
if (nPos < 0 && nCount > 0)
nPos = pStrText->GetLength();
for (int iZero = 0; iZero < nCount; iZero++)
pStrText->Insert(nPos, '0');
}
// Returns the control's value in a valid format.
CString CAMSEdit::NumericBehavior::_GetValidText() const
{
CString strText = m_pEdit->GetText();
CString strNewText;
bool bIsNegative = false;
// 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 (c == m_cNegativeSign && IsNegativeAllowed())
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)
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++;
}
}
// Check if we need to pad the number with zeros after the decimal point
if (m_nMaxDecimalPlaces > 0 && nNewLen > 0 &&
((m_uFlags & PadWithZerosAfterDecimalWhenTextChanges) ||
(!m_bAdjustingSeparators && (m_uFlags & PadWithZerosAfterDecimalWhenTextIsSet))))
{
if (nDecimalPos < 0)
{
if (nNewLen == 0 || strNewText == '-')
{
strNewText = '0';
nNewLen = 1;
}
strNewText += m_cDecimalPoint;
nDecimalPos = nNewLen++;
}
InsertZeros(&strNewText, -1, m_nMaxDecimalPlaces - (nNewLen - nDecimalPos - 1));
}
// Insert the negative sign if it's there
if (bIsNegative)
strNewText.Insert(0, m_cNegativeSign);
return GetSeparatedText(strNewText);
}
// Handles the WM_CHAR message, which is called when the user enters a regular character or Backspace
void CAMSEdit::NumericBehavior::_OnChar(UINT uChar, UINT nRepCnt, UINT nFlags)
{
// Check to see if it's read only
if (m_pEdit->IsReadOnly())
return;
TCHAR c = static_cast<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 && _istprint(c))
{
TCHAR cPrefix = m_strPrefix[nStart];
// Check if it's the same character as the prefix.
if (cPrefix == c && _ShouldEnter(c))
{
if (nLen > nStart)
{
nEnd = (nEnd == nLen ? nEnd : (nStart + 1));
m_pEdit->SetSel(nStart, nEnd);
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))
{
nEnd = (nEnd == nLen ? nEnd : (nPrefixLen));
m_pEdit->SetSel(nStart, nEnd);
m_pEdit->ReplaceSel(m_strPrefix.Mid(nStart), TRUE);
NumericBehavior::_OnChar(uChar, nRepCnt, nFlags);
}
return;
}
// Check if it's a negative sign
if (c == m_cNegativeSign && IsNegativeAllowed())
{
// If it's at the beginning, determine if it should overwritten
if (nStart == nPrefixLen)
{
if (!strNumericText.IsEmpty() && strNumericText[0] == m_cNegativeSign && _ShouldEnter(c))
{
nEnd = (nEnd == nLen ? nEnd : (nStart + 1));
m_pEdit->SetSel(nStart, nEnd);
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)
{
// Check if we're replacing the decimal point
if (nDecimalPos >= nStart && nDecimalPos < nEnd)
bNeedAdjustment = true;
else
{ // Otherwise, put the caret on it
if (_ShouldEnter(c))
m_pEdit->SetSel(nDecimalPos + 1, nDecimalPos + 1);
return;
}
}
else
bNeedAdjustment = true;
}
// 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))
{
nEnd = (nEnd == nLen ? nEnd : (nStart + 1));
m_pEdit->SetSel(nStart, nEnd);
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)
{
if (m_uFlags & AddDecimalAfterMaxWholeDigits && m_nMaxDecimalPlaces > 0)
{
nEnd = (nEnd == nLen ? nEnd : (nStart + 2));
m_pEdit->SetSel(nStart, nEnd);
m_pEdit->ReplaceSel(CString(m_cDecimalPoint) + c, TRUE);
}
return;
}
if (strNumericText.Mid(0, nNumericDecimalPos >= 0 ? nNumericDecimalPos : nNumericLen).GetLength() == m_nMaxWholeDigits + bIsNegative)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -