📄 amsedit.cpp
字号:
}
if (_ShouldEnter(c))
Behavior::_OnChar(uChar, nRepCnt, nFlags);
}
#endif // (AMSEDIT_COMPILED_CLASSES & AMSEDIT_ALPHANUMERIC_CLASS)
#if (AMSEDIT_COMPILED_CLASSES & AMSEDIT_MASKED_CLASS)
/////////////////////////////////////////////////////////////////////////////
// CAMSEdit::MaskedBehavior
// Constructs the object using the given mask.
CAMSEdit::MaskedBehavior::MaskedBehavior(CAMSEdit* pEdit, const CString& strMask /*= _T("")*/) :
Behavior(pEdit),
m_strMask(strMask)
{
m_arraySymbols.Add(Symbol('#', _istdigit)); // default mask symbol
}
// Returns the mask
const CString& CAMSEdit::MaskedBehavior::GetMask() const
{
return m_strMask;
}
// Sets the mask and redraws the control to accomodate it
void CAMSEdit::MaskedBehavior::SetMask(const CString& strMask)
{
if (m_strMask == strMask)
return;
m_strMask = strMask;
_Redraw();
}
// Returns the numeric portion of the control's value as a string
CString CAMSEdit::MaskedBehavior::GetNumericText() const
{
CString strText = m_pEdit->GetText();
CString strResult;
for (int iPos = 0, nLen = strText.GetLength(); iPos < nLen; iPos++)
{
TCHAR c = strText[iPos];
if (_istdigit(c))
strResult += c;
}
return strResult;
}
// Returns the control's value in a valid format.
CString CAMSEdit::MaskedBehavior::_GetValidText() const
{
CString strText = m_pEdit->GetText();
int nMaskLen = m_strMask.GetLength();
// If the mask is empty, allow anything
if (!nMaskLen)
return strText;
CString strNewText;
// Accomodate the text to the mask as much as possible
for (int iPos = 0, iMaskPos = 0, nLen = strText.GetLength(); iPos < nLen; iPos++, iMaskPos++)
{
TCHAR c = strText[iPos];
TCHAR cMask = static_cast<TCHAR>(iMaskPos < nMaskLen ? m_strMask[iMaskPos] : 0);
// If we've reached the end of the mask, break
if (!cMask)
break;
// Match the character to any of the symbols
for (int iSymbol = 0, nSymbolCount = m_arraySymbols.GetSize(); iSymbol < nSymbolCount; iSymbol++)
{
const Symbol& symbol = m_arraySymbols[iSymbol];
// Find the symbol that applies for the given character
if (cMask != symbol || !symbol.Validate(c))
continue;
// Try to add matching characters in the mask until a different symbol is reached
for (; iMaskPos < nMaskLen; iMaskPos++)
{
cMask = m_strMask[iMaskPos];
if (cMask == symbol)
{
strNewText += symbol.Convert(c);
break;
}
else
{
for (int iSymbol2 = 0; iSymbol2 < nSymbolCount; iSymbol2++)
{
if (cMask == m_arraySymbols[iSymbol2])
{
strNewText += symbol.Convert(c);
break;
}
}
if (iSymbol2 < nSymbolCount)
break;
strNewText += cMask;
}
}
break;
}
// If the character was not matched to a symbol, stop
if (iSymbol == nSymbolCount)
{
if (c == cMask)
{
// Match the character to any of the symbols
for (iSymbol = 0; iSymbol < nSymbolCount; iSymbol++)
{
if (cMask == m_arraySymbols[iSymbol])
break;
}
if (iSymbol == nSymbolCount)
{
strNewText += c;
continue;
}
}
break;
}
}
return strNewText;
}
// Handles the WM_CHAR message, which is called when the user enters a regular character or Backspace
void CAMSEdit::MaskedBehavior::_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);
// If the mask is empty, allow anything
int nMaskLen = m_strMask.GetLength();
if (!nMaskLen)
{
if (_ShouldEnter(c))
Behavior::_OnChar(uChar, nRepCnt, nFlags);
return;
}
// Check that we haven't gone past the mask's length
int nStart, nEnd;
m_pEdit->GetSel(nStart, nEnd);
if (nStart >= nMaskLen && c != VK_BACK)
return;
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;
}
TCHAR cMask = m_strMask[nStart];
// Check if the mask's character matches with any of the symbols in the array.
for (int iSymbol = 0, nSymbolCount = m_arraySymbols.GetSize(); iSymbol < nSymbolCount; iSymbol++)
{
const Symbol& symbol = m_arraySymbols[iSymbol];
if (cMask == symbol)
{
if (symbol.Validate(c) && _ShouldEnter(c))
{
nEnd = (nEnd == nLen ? nEnd : (nStart + 1));
m_pEdit->SetSel(nStart, nEnd);
m_pEdit->ReplaceSel(CString(symbol.Convert(c)), TRUE);
}
return;
}
}
// Check if it's the same character as the mask.
if (cMask == c && _ShouldEnter(c))
{
nEnd = (nEnd == nLen ? nEnd : (nStart + 1));
m_pEdit->SetSel(nStart, nEnd);
m_pEdit->ReplaceSel(CString(c), TRUE);
return;
}
// Concatenate all the mask symbols
CString strSymbols;
for (iSymbol = 0; iSymbol < nSymbolCount; iSymbol++)
strSymbols += m_arraySymbols[iSymbol];
// If it's a valid character, find the next symbol on the mask and add any non-mask characters in between.
for (iSymbol = 0; iSymbol < nSymbolCount; iSymbol++)
{
const Symbol& symbol = m_arraySymbols[iSymbol];
// See if the character is valid for any other symbols
if (!symbol.Validate(c))
continue;
// Find the position of the next symbol
CString strMaskPortion = m_strMask.Mid(nStart);
int nMaskPos = strMaskPortion.FindOneOf(strSymbols);
// Enter the character if there isn't another symbol before it
if (nMaskPos >= 0 && strMaskPortion[nMaskPos] == symbol && _ShouldEnter(c))
{
m_pEdit->SetSel(nStart, nStart + nMaskPos);
m_pEdit->ReplaceSel(strMaskPortion.Left(nMaskPos), TRUE);
_OnChar(uChar, nRepCnt, nFlags);
return;
}
}
}
// Handles the WM_KEYDOWN message, which is called when the user enters a special character such as Delete or the arrow keys.
void CAMSEdit::MaskedBehavior::_OnKeyDown(UINT uChar, UINT nRepCnt, UINT nFlags)
{
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;
}
}
Behavior::_OnKeyDown(uChar, nRepCnt, nFlags);
}
// Returns a reference to the array of symbols that may be found on the mask.
// This allows adding, editing, or deleting symbols for the mask.
CAMSEdit::MaskedBehavior::SymbolArray& CAMSEdit::MaskedBehavior::GetSymbolArray()
{
return m_arraySymbols;
}
/////////////////////////////////////////////////////////////////////////////
// CAMSEdit::MaskedBehavior::Symbol
// Constructs the object -- needed for CArray
CAMSEdit::MaskedBehavior::Symbol::Symbol() :
m_cSymbol(0),
m_fnValidation(NULL),
m_fnConversion(NULL)
{
}
// Constructs the object with the given character and set of functions
CAMSEdit::MaskedBehavior::Symbol::Symbol(TCHAR cSymbol, ValidationFunction fnValidation, ConversionFunction fnConversion /*= NULL*/) :
m_cSymbol(cSymbol),
m_fnValidation(fnValidation),
m_fnConversion(fnConversion)
{
}
// Destroys the object (virtual).
CAMSEdit::MaskedBehavior::Symbol::~Symbol()
{
}
// Returns true if the given character (usually just entered by the user) is a match for self's symbol.
// This is tested by passing it to the validation function passed in the constructor (if valid).
bool CAMSEdit::MaskedBehavior::Symbol::Validate(TCHAR c) const
{
if (m_fnValidation)
return (m_fnValidation(c) != 0);
return true;
}
// Returns the given character converted as a result of calling the conversion function was passed in the constructor.
// If no conversion function was passed, the character is returned intact.
TCHAR CAMSEdit::MaskedBehavior::Symbol::Convert(TCHAR c) const
{
if (m_fnConversion)
return (TCHAR)m_fnConversion(c);
return c;
}
// Sets the character for the symbol to be used in the mask.
void CAMSEdit::MaskedBehavior::Symbol::Set(TCHAR cSymbol)
{
m_cSymbol = cSymbol;
}
// Returns the character for the symbol to be used in the mask.
TCHAR CAMSEdit::MaskedBehavior::Symbol::Get() const
{
return m_cSymbol;
}
// Returns the character for the symbol to be used in the mask.
CAMSEdit::MaskedBehavior::Symbol::operator TCHAR() const
{
return m_cSymbol;
}
#endif // (AMSEDIT_COMPILED_CLASSES & AMSEDIT_MASKED_CLASS)
#if (AMSEDIT_COMPILED_CLASSES & AMSEDIT_NUMERIC_CLASS)
/////////////////////////////////////////////////////////////////////////////
// CAMSEdit::NumericBehavior
// Constructs the object using the given nMaxWholeDigits and nMaxDecimalPlaces.
CAMSEdit::NumericBehavior::NumericBehavior(CAMSEdit* pEdit, int nMaxWholeDigits /*= 9*/, int nMaxDecimalPlaces /*= 4*/) :
Behavior(pEdit),
m_nMaxWholeDigits(nMaxWholeDigits >= 0 ? nMaxWholeDigits : -nMaxWholeDigits),
m_nMaxDecimalPlaces(nMaxDecimalPlaces),
m_cNegativeSign('-'),
m_cDecimalPoint('.'),
m_cGroupSeparator(','),
m_nDigitsInGroup(0),
m_dMin(AMS_MIN_NUMBER),
m_dMax(AMS_MAX_NUMBER),
m_bAdjustingSeparators(false)
{
ASSERT(m_nMaxWholeDigits > 0); // must have at least 1 digit to the left of the decimal
ASSERT(m_nMaxDecimalPlaces >= 0); // decimal places must be positive
if (nMaxWholeDigits < 0)
m_uFlags |= CannotBeNegative;
// Get the system's negative sign
if (::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNEGATIVESIGN, NULL, 0))
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SNEGATIVESIGN, &m_cNegativeSign, sizeof(m_cNegativeSign));
// Get the system's decimal point
if (::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, NULL, 0))
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, &m_cDecimalPoint, sizeof(m_cDecimalPoint));
// Get the system's group separator
if (::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, NULL, 0))
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, &m_cGroupSeparator, sizeof(m_cGroupSeparator));
// Ensure the separators are not the same
if (m_cDecimalPoint == m_cGroupSeparator)
m_cGroupSeparator = (m_cDecimalPoint == ',' ? '.' : ',');
}
// Sets the maximum number of digits before the decimal point.
// If nMaxWholeDigits is negative, then negative numbers will NOT be allowed.
void CAMSEdit::NumericBehavior::SetMaxWholeDigits(int nMaxWholeDigits)
{
ASSERT(nMaxWholeDigits);
// If nMaxWholeDigits is negative, don't allow negatives
bool bAllowNegative = (nMaxWholeDigits >= 0);
if (nMaxWholeDigits < 0)
nMaxWholeDigits = -nMaxWholeDigits;
if (m_nMaxWholeDigits == nMaxWholeDigits && IsNegativeAllowed() == bAllowNegative)
return;
m_nMaxWholeDigits = nMaxWholeDigits;
if (!ModifyFlags(bAllowNegative ? 0 : CannotBeNegative, bAllowNegative ? CannotBeNegative : 0))
_Redraw();
}
// Returns the maximum number of digits before the decimal point.
int CAMSEdit::NumericBehavior::GetMaxWholeDigits() const
{
return m_nMaxWholeDigits;
}
// Sets the maximum number of digits after the decimal point.
void CAMSEdit::NumericBehavior::SetMaxDecimalPlaces(int nMaxDecimalPlaces)
{
ASSERT(nMaxDecimalPlaces >= 0);
if (m_nMaxDecimalPlaces == nMaxDecimalPlaces)
return;
m_nMaxDecimalPlaces = nMaxDecimalPlaces;
_Redraw();
}
// Returns the maximum number of digits after the decimal point.
int CAMSEdit::NumericBehavior::GetMaxDecimalPlaces() const
{
return m_nMaxDecimalPlaces;
}
// Sets whether the negative sign is allowed in the number or not.
void CAMSEdit::NumericBehavior::AllowNegative(bool bAllowNegative /*= true*/)
{
ModifyFlags(bAllowNegative ? 0 : CannotBeNegative, bAllowNegative ? CannotBeNegative : 0);
}
// Returns true if the negative sign is allowed in the number.
bool CAMSEdit::NumericBehavior::IsNegativeAllowed() const
{
return !(m_uFlags & CannotBeNegative);
}
// Sets the number of digits to be grouped together (if any).
void CAMSEdit::NumericBehavior::SetDigitsInGroup(int nDigitsInGroup)
{
ASSERT(nDigitsInGroup >= 0);
if (m_nDigitsInGroup == nDigitsInGroup)
return;
m_nDigitsInGroup = nDigitsInGroup;
_Redraw();
}
// Returns the number of digits to be grouped together (if any).
int CAMSEdit::NumericBehavior::GetDigitsInGroup() const
{
return m_nDigitsInGroup;
}
// Sets the character to use for the decimal point and the group separator (thousands)
void CAMSEdit::NumericBehavior::SetSeparators(TCHAR cDecimal, TCHAR cGroup)
{
ASSERT(cDecimal);
ASSERT(cGroup);
// If nothing's changing, leave
if (m_cDecimalPoint == cDecimal && m_cGroupSeparator == cGroup)
return;
// Set them
m_cDecimalPoint = cDecimal;
m_cGroupSeparator = cGroup;
// Ensure they're not the same
if (m_cDecimalPoint == m_cGroupSeparator)
m_cGroupSeparator = (m_cDecimalPoint == ',' ? '.' : ',');
_Redraw();
}
// Retrieves the character being used for the decimal point and group separator (thousands).
void CAMSEdit::NumericBehavior::GetSeparators(TCHAR* pcDecimal, TCHAR* pcGroup) const
{
if (pcDecimal)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -