Click here to Skip to main content
15,860,972 members
Articles / Desktop Programming / MFC
Article

Validating Edit Controls

Rate me:
Please Sign up or sign in to vote.
4.86/5 (68 votes)
21 Mar 2004CPOL24 min read 686.4K   10K   163   217
CEdit-derived classes which validate the most popular types of data input.

Sample Image

Introduction
Background
Classes
Usage

Introduction

Edit controls are often used to enter dates, times, currency values, or preformatted numeric data such as phone numbers. A control that allows its user to only enter a specific type of data is useful for several reasons:

  1. The user may do less typing if the control automatically fills in characters such as dashes or slashes.
  2. The user gets immediate feedback if he/she enters an invalid character.
  3. The entered data is much more likely to be valid when the user "submits" it.

The classes presented in this article provide these benefits for the most popular types of data that may be entered: dates, times, decimals, integers, currency amounts, formatted numerics, and restricted alphanumerics.

Background

A while back I worked on a project which required edit controls with very strict behavior. One was a date control which needed to accept dates in mm/dd/yyyy format only. The user would be allowed to enter just the numbers and the slashes would be filled in automatically (unlike Microsoft’s Date control). The control would also prevent the user from messing up the format, by, for example, deleting the second character. Another edit control was used for entering dollar amounts and would automatically insert commas for the thousand’s separator.

I went on the hunt for a set of controls that would give me this behavior and I took a look at Masked Edit Control from Dundas Software. Unfortunately it wasn’t specific enough, especially when it came to dates. I needed more than just a masked control; I needed to make sure the value would always be valid. I also didn’t feel like spending time modifying or extending Dundas’s code to make it work like I needed it, so I took a big gulp and decided to do it all from scratch. What you see now is the result of that effort, which I finally got around to publishing. :-)

Classes

All classes derive from CEdit and are prefixed with CAMS (AMS are my company’s initials). The following table gives the class names and descriptions:

Class NameDescription
CAMSEdit

Base class for the classes below. It has some basic functionality.

CAMSAlphanumericEdit

Prohibits input of one or more characters and restricts length.

CAMSNumericEdit

Used to input a decimal number with a maximum number of digits before and/or after the decimal point.

CAMSIntegerEdit

Only allows a whole number to be entered.

CAMSCurrencyEdit

Inserts a monetary symbol in front of the value and a separator for the thousands.

CAMSDateEdit

Allows input of a date in the mm/dd/yyyy or dd/mm/yyyy format, depending on the locale.

CAMSTimeEdit

Allows input of a time with or without seconds and in 12 or 24 hour format, depending on the locale.

CAMSDateTimeEditAllows input of a date and time by combining the above two classes.
CAMSMaskedEdit

Takes a mask containing '#' symbols, each one corresponding to a digit. Any characters between the #s are automatically inserted as the user types. It may be customized to accept additional symbols.

CAMSMultiMaskedEdit

Takes a mask and adopts its behavior to any of the above classes.

What follows is a more detailed description of these classes and their usage. All member functions are public unless otherwise specified.

CAMSEdit

I decided to give all my CEdit-derived classes a common base class for any common methods they may need. The result is this class which only has minor enhancements to the CEdit class, but serves as a pseudo-namespace for the Behavior classes used by the CAMSEdit-derived classes.

MemberDescription

void SetText(const CString& strText)

Sets the text for the control. This text is validated against the controls proper format.

CString GetText() const

Retrieves the text in the control.

CString GetTrimmedText() const

Retrieves the text in the control without leading or trailing spaces.

void SetBackgroundColor(COLORREF rgb)

Sets the control's background color.

COLORREF GetBackgroundColor() const

Retrieves the control's background color.

void SetTextColor(COLORREF rgb)

Sets the control's text color.

COLORREF GetTextColor() const

Retrieves the control's text color.

bool IsReadOnly() const

Returns true if the control is read-only.
virtual bool ShouldEnter(TCHAR c) const;This protected member is called directly by all classes right before a typed-in character is to be shown. By default it always returns true. But you may override it (in a derived class) and make it return false if the user enters a character you don't want to allow.

CAMSAlphanumericEdit

This class is used for general alphanumeric input with the exception of whatever characters you specify to not be allowed. So if you need to prevent certain characters from being entered, this class is useful. It can also restrict the length of the text.

MemberDescription

void SetInvalidCharacters(const CString& strInvalidChars)

Sets each of characters contained in the given string to not be allowed for input. By default these characters are not allowed: %'*"+?><:\

const CString& GetInvalidCharacters() const

Retrieves the characters not allowed for input.

void SetMaxCharacters(int nMaxChars)

Sets the maximum number of characters allowed. By default there is no limit (0).

int GetMaxCharacters() const

Retrieves the maximum number of characters allowed.

CAMSNumericEdit

This is the base class for all numeric entry classes. It ensures that the user enters a valid number and provides features such as automatic formatting. It also allows you to restrict what the number can look like, such as how many digits before and after the decimal point, and whether it can be negative or not.

MemberDescription

void SetDouble(double dText, bool bTrimTrailingZeros = true)

Sets the control's text to the given double value. If bTrimTrailingZeros is true, any insignificant zeros after the decimal point are removed.

double GetDouble() const

Returns the current text as a double value.

void SetInt(int nText)

Sets the control's text to the given integer value.

int GetInt() const

Returns the current text as an integer value.

void SetMaxWholeDigits(int nMaxWholeDigits)

Sets the maximum number of digits before the decimal point. This is 9 by default.

int GetMaxWholeDigits() const

Retrieves the maximum number of digits before the decimal point.

void SetMaxDecimalPlaces(int nMaxDecimalPlaces)

Sets the maximum number of digits after the decimal point. This is 4 by default.

int GetMaxDecimalPlaces() const

Retrieves the maximum number of digits after the decimal point.

void AllowNegative(bool bAllowNegative = true)

Sets a flag to allow a negative sign or not. By default negatives are allowed.

bool IsNegativeAllowed() const

Determines whether a negative sign can be entered or not.

void SetDigitsInGroup(int nDigitsInGroup)

Sets the size of the groups of digits to be separated before the decimal point. This is 0 by default but is typically set to 3 to separate thousands.

int GetDigitsInGroup() const

Retrieves the number of digits per group shown before the decimal point.

void SetSeparator(TCHAR cDecimal, TCHAR cGroup)

Sets the character to use for the decimal point and the group separator (thousands)

void GetSeparator(TCHAR* pcDecimal, TCHAR* pcGroup) const

Retrieves the character being used for the decimal point and group separator (thousands).

void SetPrefix(const CString& strPrefix)

Sets the characters to automatically display in front of the numeric value entered. This is useful for displaying currency signs. By default it is empty.

const CString& GetPrefix() const

Retrieves the characters to automatically display in front of the numeric value entered.

void SetMask(const CString& strMask)

Parses a string containing '#', comma, and period characters to determine the format of the number that the user may enter. For example: #,###.# means: (1) allow up to 4 digits before the decimal point, (2) insert commas every 3 digits before the decimal point, (3) use a dot as the decimal point, and (4) allow up to one digit after the decimal point.

CString GetMask() const

Retrieves a string containing '#', comma, and period characters representing the format of the numeric value that the user may enter.

void SetRange(double dMin, double dMax)

Sets the range of valid numbers values allowed. By default it's AMS_MIN_NUMBER to AMS_MAX_NUMBER.

void GetRange(double* pdMin, double* pdMax) const

Retrieves the range of valid numbers allowed.

bool IsValid() const

Returns true if the number is valid and falls within the allowed range.

bool CheckIfValid(bool bShowErrorIfNotValid = true)

Returns true if the number is valid and optionally shows an error message if not.

void ModifyFlags(UINT uAdd, UINT uRemove)

Allows adding or removing flags from the control. This may used to set/clear the flags below to alter the behavior of the control:

AddDecimalAfterMaxWholeDigits

Inserts the decimal symbol automatically when the user enters a digit and all the whole numbers have already been entered.

PadWithZerosAfterDecimalWhenTextChanges

Automatically pads the number with zeros after the decimal point any time the text is changed (using SetWindowText or a key stroke).

PadWithZerosAfterDecimalWhenTextIsSet

Automatically pads the number with zeros after the decimal point any time the text is set (using SetWindowText).

OnKillFocus_PadWithZerosBeforeDecimal

Pads the number with zeros before the decimal symbol up to the max allowed (set by SetMaxWholeDigits).

OnKillFocus_PadWithZerosAfterDecimal

Pads the number with zeros after the decimal symbol up to the max allowed (set by SetMaxDecimalPlaces).

OnKillFocus_DontPadWithZerosIfEmpty

When combined with any of the above two "Pad" flags, the value is not padded if it's empty.

OnKillFocus_Beep_IfInvalid

Beeps if the value is not a valid number.

OnKillFocus_Beep_IfEmpty

Beeps if the no value has been entered.

OnKillFocus_Beep

Beeps if the value is not valid or has not been entered.

OnKillFocus_SetValid_IfInvalid

Changes the value to a valid number if it isn't.

OnKillFocus_SetValid_IfEmpty

Fills in a valid number value if the control is empty.

OnKillFocus_SetValid

Sets the value to a valid number if it's empty or not valid.

OnKillFocus_SetFocus_IfInvalid

Sets the focus back to the control if its value is not valid.

OnKillFocus_SetFocus_IfEmpty

Sets the focus back to the control if it doesn't contain a value.

OnKillFocus_SetFocus

Sets the focus back to the control if it's empty or not valid.

OnKillFocus_ShowMessage_IfInvalid

Shows an error message box if the value is not a valid number.

OnKillFocus_ShowMessage_IfEmpty

Shows an error message box if it doesn't contain a value.

OnKillFocus_ShowMessage

Shows an error message box if its empty of not valid.

CAMSIntegerEdit

This class is used to only allow integer values to be entered. It is derived from

CAMSCurrencyEdit

This class is used for entering monetary values. It is also derived from CAMSNumericEdit but it sets the prefix to the currency sign specified in the locale (such as a '$'). It also separates thousands using the character specified in the locale (such as a comma). And it sets the maximum number of digits after the decimal point to two.

CAMSDateEdit

This class handles dates in a very specific format: mm/dd/yyyy or dd/mm/yyyy, depending on the locale. As the user enters the digits, the slashes are automatically filled in. The user may only remove characters from the right side of the value entered. This ensures that the value is kept in the proper format. As a bonus, the user may use the up/down arrow keys to increment/decrement the month, day, or year, depending on the location of the caret.

MemberDescription

void SetDate(int nYear, int nMonth, int nDay)

Sets the date value.

void SetDate(const CTime& date)

Sets the date value.

void SetDate(const COleDateTime& date)

Sets the date value.

void SetDateToToday()

Sets the date value to today's date.

CTime GetDate() const

Retrieves the date (with zeros for the hour, minute, and second).

COleDateTime GetOleDate() const

Retrieves the date (with zeros for the hour, minute, and second).

int GetYear() const

Retrieves the year.

int GetMonth() const

Retrieves the month

int GetDay() const

Retrieves the day

void SetYear(int nYear)

Sets the year.

void SetMonth(int nMonth)

Sets the month

void SetDay(int nDay)

Sets the day

bool IsValid() const

Returns true if the date value is valid.

bool CheckIfValid(bool bShowErrorIfNotValid = true)

Returns true if the date is valid and optionally shows an error message if not.

void SetRange(const CTime& dateMin, const CTime& dateMax)

Sets the range of valid date values allowed. By default it's 01/01/1900 to 12/31/9999.

void SetRange(const COleDateTime& dateMin, const COleDateTime& dateMax)

Sets the range of valid date values allowed.

void GetRange(CTime* pDateMin, CTime* pDateMax) const

Retrieves the range of valid dates allowed.

void GetRange(COleDateTime* pDateMin, COleDateTime* pDateMax) const

Retrieves the range of valid dates allowed.

void SetSeparator(TCHAR cSep)

Sets the character used to separate the date's components. By default it's a slash ('/').

TCHAR GetSeparator() const

Retrieves the character used to separate the date components.

void ShowDayBeforeMonth (bool bDayBeforeMonth = true)

Overrides the locale's format and based on the flag sets the day to be shown before or after the month.

bool IsDayShownBeforeMonth () const

Returns true if the day will be shown before the month (dd/mm/yyyy).

void ModifyFlags(UINT uAdd, UINT uRemove)

Allows adding or removing flags from the control. This may used to set/clear the flags below to alter the behavior of the control when it loses focus:

OnKillFocus_Beep_IfInvalid

Beeps if the value is not a valid date.

OnKillFocus_Beep_IfEmpty

Beeps if the no value has been entered.

OnKillFocus_Beep

Beeps if the value is not valid or has not been entered.

OnKillFocus_SetValid_IfInvalid

Changes the value to a valid date if it isn't.

OnKillFocus_SetValid_IfEmpty

Fills in a valid date value (today's date if allowed) if the control is empty.

OnKillFocus_SetValid

Sets the value to a valid date if it's empty or not valid.

OnKillFocus_SetFocus_IfInvalid

Sets the focus back to the control if its value is not valid.

OnKillFocus_SetFocus_IfEmpty

Sets the focus back to the control if it doesn't contain a value.

OnKillFocus_SetFocus

Sets the focus back to the control if it's empty or not valid.

OnKillFocus_ShowMessage_IfInvalid

Shows an error message box if the value is not a valid date.

OnKillFocus_ShowMessage_IfEmpty

Shows an error message box if it doesn't contain a value.

OnKillFocus_ShowMessage

Shows an error message box if its empty of not valid.

CAMSTimeEdit

This class handles times in a very specific format: HH:mm or hh:mm AM, depending on the locale. Seconds are also supported, but not by default. As the user enters the digits, the colons are automatically filled in. The user may only remove characters from the right side of the value entered. This ensures that the value is kept in the proper format. As a bonus, the user may use the up/down arrow keys to increment/decrement the hour, minute, second, or AM/PM, depending on the location of the caret.

MemberDescription

void SetTime(int nHour, int nMinute, int nSecond = 0)

Sets the time value.

void SetTime(const CTime& date)

Sets the time value using the time portion of the given date.

void SetTime(const COleDateTime& date)

Sets the time value using the time portion of the given date

void SetTimeToNow()

Sets the time value to the current time.

CTime GetTime() const

Retrieves the time (with Dec 30, 1899 for the date).

COleDateTime GetOleTime() const

Retrieves the time (with Dec 30, 1899 for the date).

int GetHour() const

Retrieves the hour.

int GetMinute() const

Retrieves the minute.

int GetSecond() const

Retrieves the second.

CString GetAMPM() const

Returns the AM/PM symbol currently shown on the control or an empty string.

void SetHour(int nYear)

Sets the hour.

void SetMinute(int nMonth)

Sets the minute.

void SetSecond(int nDay)

Sets the second.

void SetAMPM(bool bAM)

Sets the AM or PM symbol if not in 24 hour format.

bool IsValid(bool bCheckRangeAlso = true) const

Returns true if the time value is valid. If bCheckRangeAlso is true, the time value is also checked that it falls between the range of times established by the SetRange function.

bool CheckIfValid(bool bShowErrorIfNotValid = true)

Returns true if the time is valid and is in range, and optionally shows an error message if not.

void SetRange(const CTime& dateMin, const CTime& dateMax)

Sets the range of valid time values allowed. By default it's 00:00:00 to 23:59:59.

Note: While the control has focus, the user will be allowed to input any value between 00:00:00 and 23:59:59, regardless of what values are passed to SetRange.

void SetRange(const COleDateTime& dateMin, const COleDateTime& dateMax)

Sets the range of valid time values allowed.

void GetRange(CTime* pDateMin, CTime* pDateMax) const

Retrieves the range of valid times allowed.

void GetRange(COleDateTime* pDateMin, COleDateTime* pDateMax) const

Retrieves the range of valid times allowed.

void SetSeparator(TCHAR cSep)

Sets the character used to separate the time's components. By default it's a colon (':').

TCHAR GetSeparator() const

Retrieves the character used to separate the date components.

void Show24HourFormat (bool bShow24HourFormat = true)

Overrides the locale's format and based on the flag sets the hour to go from 00 to 23 (24 hour format) or from 01 to 12 with the AM/PM symbols.

bool IsShowing24HourFormat () const

Returns true if the hour will be shown in 24 hour format (instead of 12 hour format with the AM/PM symbols).

void ShowSeconds (bool bShowSeconds = true)

Sets whether the seconds will be shown or not.

bool IsShowingSeconds () const

Returns true if the seconds will be shown.

void SetAMPMSymbols(const CString& strAM, const CString& strPM)

Overrides the locale's format and sets the symbols to display for AM and PM, which may be of any length but must both be of the same length.

void GetAMPMSymbols(CString* pStrAM, CString* pStrPM) const

Retrieves the symbols to display for AM and PM into the given CString pointers.

void ModifyFlags(UINT uAdd, UINT uRemove)

Allows adding or removing flags from the control. This may used to set/clear the flags below to alter the behavior of the control when it loses focus:

OnKillFocus_Beep_IfInvalid

Beeps if the value is not a valid date.

OnKillFocus_Beep_IfEmpty

Beeps if the no value has been entered.

OnKillFocus_Beep

Beeps if the value is not valid or has not been entered.

OnKillFocus_SetValid_IfInvalid

Changes the value to a valid date if it isn't.

OnKillFocus_SetValid_IfEmpty

Fills in a valid date value (today's date if allowed) if the control is empty.

OnKillFocus_SetValid

Sets the value to a valid date if it's empty or not valid.

OnKillFocus_SetFocus_IfInvalid

Sets the focus back to the control if its value is not valid.

OnKillFocus_SetFocus_IfEmpty

Sets the focus back to the control if it doesn't contain a value.

OnKillFocus_SetFocus

Sets the focus back to the control if it's empty or not valid.

OnKillFocus_ShowMessage_IfInvalid

Shows an error message box if the value is not a valid date.

OnKillFocus_ShowMessage_IfEmpty

Shows an error message box if it doesn't contain a value.

OnKillFocus_ShowMessage

Shows an error message box if its empty of not valid.

CAMSDateTimeEdit

This class multiply inherits from the Date and Time behaviors to show a date and time value separated by a space. It contains all the functions of the CAMSDateEdit and CAMSTimeEdit classes, plus a few of its own. In addition, this class can dynamically be changed to only accept a date or a time value, using the ModifyFlags function.

MemberDescription

void SetDateTime(int nHour, int nMinute, int nSecond = 0)

Sets the date and time value.

void SetDateTime(const CTime& date)

Sets the date and time value from the given CTime object.

void SetDateTime(const COleDateTime& date)

Sets the date and time value from the given COleDateTime object.

void SetToNow()

Sets the date and time value to the current date and time.

CTime GetDateTime() const

Retrieves the date and time into a CTime object.

COleDateTime GetOleDateTime() const

Retrieves the time and time into a CTime object.

bool IsValid() const

Returns true if the date and time value is valid.

bool CheckIfValid(bool bShowErrorIfNotValid = true)

Returns true if the date and time is valid and is in range, and optionally shows an error message if not.

void SetRange(const CTime& dateMin, const CTime& dateMax)

Sets the range of valid date values allowed. By default it's 01/01/1900 00:00:00 to 12/31/9999 23:59:59.

void SetRange(const COleDateTime& dateMin, const COleDateTime& dateMax)

Sets the range of valid time values allowed.

void GetRange(CTime* pDateMin, CTime* pDateMax) const

Retrieves the range of valid times allowed.

void GetRange(COleDateTime* pDateMin, COleDateTime* pDateMax) const

Retrieves the range of valid times allowed.

void SetSeparator(TCHAR cSep, bool bDate)

Sets the character used to separate the date or the time components. By default it's a slash ('/') for the date, or the colon (':') for the time.

TCHAR GetSeparator(bool bDate) const

Retrieves the character used to separate the date or the time components.

void ModifyFlags(UINT uAdd, UINT uRemove)

Allows adding or removing flags from the control. This may used to set/clear the same flags in the <a href="#CAMSDateEdit">CAMSDateEdit</a> and <a href="#CAMSTimeEdit">CAMSTimeEdit</a> classes, plus these:

DateOnly

Changes this class to only allow a date value, just like the CAMSDateEdit class.

TimeOnly

Changes this class to only allow a time value, just like the CAMSTimeEdit class.
Note: If both of these flags are set, the TimeOnly flag is ignored.

CAMSMaskedEdit

This class is useful for values with a fixed numeric format, such as phone numbers, social security numbers, or zip codes.

MemberDescription

void SetMask(const CString& strMask)

Sets the format of the values to be entered. By default, each '#' symbol in the mask represents a digit. Any other characters in between the # symbols are automatically filled-in as the user types digits.

Additional characters may be added to be interpreted as special mask symbols. See GetSymbolArray below.

const CString& GetMask() const

Retrieves the mask used to format the value entered by the user.

CString GetNumericText() const

Retrieves the control's value without any non-numeric characters.

SymbolArray& GetSymbolArray ()

Retrieves a reference to the array of symbols that may be found on the mask. By default, this array will contain one element for the # symbol.

Use this function to add, edit, or delete symbols (see the CAMSEDit::MaskedBehavior::Symbol class in amsEdit.h). Here are some examples of how to use this function to add additional symbols:

// Add the '?' symbol to allow alphabetic
// characters.
m_ctlMasked.GetSymbolArray().Add(
  CAMSMaskedEdit::Symbol('?', _istalpha));

// Add the '{' symbol to allow alphabetic
// characters and then convert them to uppercase.
m_ctlMasked.GetSymbolArray().Add(
  CAMSMaskedEdit::Symbol('{', _istalpha,
  _totupper));

CAMSMultiMaskedEdit

This class is capable of dynamically taking on the behavior of any of the above classes based on the mask assigned to it. See SetMask below for more details. It contains not only it's own member functions but also those of the Alphanumeric, Numeric, Masked, and DateTime classes above. With such high overhead, I recommend you only use this class for controls which must dynamically change from one behavior to another at run time. The default behavior is Alphanumeric.

MemberDescription

void SetMask(const CString& strMask)

Sets the format of the values to be entered.

  • ##/##/#### ##:##:## = Date and time (with seconds).
    The location of the month and the hour format are retrieved from the locale.
  • ##/##/#### ##:## = Date and time (without seconds).
    The location of the month and the hour format are retrieved from the locale.
  • ##/##/#### = Date.
    The location of the month is retrieved from the locale.
  • ##:##:## = Time (with seconds).
    The location of hour format is retrieved from the locale.
  • ##:## = Time (without seconds).
    The location of hour format is retrieved from the locale.
If it looks like a numeric value, such as ### or #,###.### (without foreign characters after the first #) then it's treated as a number; otherwise it's treated as a masked value (e.g., ###-####).

const CString& GetMask() const

Retrieves the mask used to format the value entered by the user.

Usage

These classes are designed to be used inside CDialog-derived classes as replacements for the CEdit variables typically created with the ClassWizard. Here's what you need to use them inside your project:

  1. Add amsEdit.cpp and amsEdit.h to your project.
  2. Include amsEdit.h inside your sources. I recommend including it inside stdafx.h so that it's only done in one place.
  3. Add edit controls to your dialog resource inside DevStudio.
  4. Use the "Member Variables" tab of the ClassWizard to associate your edit controls to CEdit variables.
  5. After closing ClassWizard, open the dialog's header file and change the type of the controls you need to validate from CEdit to one of the CAMSEdit-derived classes above.
  6. If necessary, use the OnInitDialog handler to adjust any settings, such as initial values, ranges, etc. For example if you have a CAMSDateEdit class, you would probably want to set its date ranges using the SetRange member.
  7. Enjoy!

Note: If you need to keep your executable as small as possible, you can change the AMSEDIT_COMPILED_CLASSES macro (defined in amsEdit.h) to compile just the classes you need to use. Also, if you want to build and export these classes in an MFC Extension DLL, look inside amsEdit.h for instructions.

History

Version 1.0

Apr 9, 2002

  • Fixed incorrect behavior of the up/down arrow keys in CAMSDateEdit whenever the date would appear in dd/mm/yyyy format. Thanks to spleen for reporting it.

Apr 21, 2002

  • Fixed incorrect handling of numerics when the locale is set to use a comma for the decimal point and a period for the thousand's separator. Thanks to Anonymous for "pointing" it out.

Version 2.0

Jan 28, 2003

  • Added the CAMSTimeEdit class to allow input of time values. Many thanks to Paul Runstedler for providing me with his version of the class.
  • Added a section to the demo's dialog box to show the new CAMSTimeEdit class in action.
  • Added the CAMSDateTimeEdit class to allow input of date and time values in the same edit box. This class multiply inherits from the DateBehavior and TimeBehavior classes.
  • Enhanced the MaskedBehavior class to allow any character (in addition to the '#') to be interpreted as a special mask symbol. Thanks to Paul Runstedler for providing me with his code, which gave me the idea to add this feature.
  • Added OnKillFocus flags to the NumericBehavior class to allow padding of the value with zeros before and/or after the decimal point. This is especially useful when entering monetary values, so I added it to the CAMSCurrencyEdit class. Thanks to Spiros Prantalos for giving me the idea.
  • Changed the NumericBehavior to automatically put a zero in front of values that start with a decimal symbol when the control loses focus (ie. ".69" becomes "0.69").
  • Added AddDecimalAfterMaxWholeDigits flag to allow the decimal point to be automatically inserted when the user enters a digit and all the whole numbers have already been entered. Thanks to Spiros Prantalos for giving me the idea.
  • Fixed a bug with the date validation code (IsValidMonth). Thanks to Hakon for reporting it.
  • Added GetTrimmedText to the CAMSEdit class. Thanks to Paul Runstedler for providing me with his code.
  • Replaced the GetTextAsLong and GetTextAsDouble functions with GetInt and GetDouble inside the CAMSNumericEdit class (which propagates to the CAMSIntegerEdit and CAMSCurrencyEdit classes). I also added SetInt and SetDouble to make it easy to set the text to an int or double value.
  • Added comments to the top of all the functions and shuffled some code around to make it cleaner and easier to maintain.

Feb 14, 2003

  • Got the project to build successfully in Visual Studio .NET, after fixing a few minor issues.
  • Added virtual destructors that were missing in two classes containing virtual functions.
  • Added IsReadOnly to CAMSEdit and fixed a bug that was allowing input even when the control was read-only. Thanks to solopido for reporting it.

Mar 4, 2003

  • Added passive range checking to the NumericBehavior class. This means that if a range has been set and any of the OnKillFocus flags are set, the value will be verified when the control loses focus. Thanks to Anatoly Sidorov for requesting it.
  • Added the ability to change and retrieve the separators for numeric values (NumericBehavior) -- the decimal symbol and the thousand's separator. Thanks to João Paulo Figueira for giving me the idea.
  • Fixed a bug that was causing the NumericBehavior's value to be refreshed unnecessarily and thus causing extra EN_CHANGE messages to be sent. Thanks to Anatoly Sidorov for reporting it.
  • Cleaned up the code even further and fixed minor issues with the TimeBehavior.

Sep 25, 2003

  • Fixed a problem related to adding masked symbols with overlapping character validations, reported by G. Steudtel. Thanks to G. Steudtel and Spiros for providing the solution to the problem.
  • Fixed a bug that would cause a crash when selecting text and pressing Shift+Delete, originally reported by Raffaele Romito. Thanks to Matteo (Teo77) for also reporting it and then providing me with the solution.

Version 3.0

Mar 18, 2004

  • Fixed bugs in NumericBehavior class related to decimal and thousand's separators for non-US locales. Thanks to Carlos Marsura for reporting and suggesting a fix the problem.
  • Added _tsetlocale(LC_ALL, _T("")); inside OnInitDialog of the Demo to make it use the current user's locale. This isn't done by the underlying code! Doing this fixes problems with conversions between string and double values in locales where the decimal point is not a dot. Thanks to JNKS for reporting this problem along with a workaround.
  • Added the PadWithZerosAfterDecimalWhenTextChanges and PadWithZerosAfterDecimalWhenTextIsSet flags to the NumericBehavior class to allow automatic padding with zeros. I then set the PadWithZerosAfterDecimalWhenTextIsSet flag into the CAMSCurrencyEdit class so that the ".00" would be automatically appended (if necessary).
  • Added a call to IsReadOnly to prevent the Up/Down arrows from changing the Date and Time controls when read-only.
  • Made minor adjustments to get the code to compile with no warnings on Warning Level 4. Thanks to Jim Chekerylla and Carlo Masura for their comments and suggestions.
  • Fixed minor bug with the MaskedBehavior class related to deletion occurring when using custom symbols.
  • Added AMSEDIT_EXPORT to each class declaration to make it easy to export the code from an MFC Extension DLL if desired. See amsEdit.h for more details.
  • Broke each class into #if blocks to allow them to be selectively compiled using the new AMSEDIT_COMPILED_CLASSES macro defined at the top of amsEdit.h. This helps to reduce the executable's size. Thanks to Michael Mann for the idea.
<a href="#CAMSNumericEdit">CAMSNumericEdit</a> so it contains all of its member, except SetDouble, GetDouble, and SetMaxDecimalPlaces which don't make sense (thus are private).

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
I've done extensive work with C++, MFC, COM, and ATL on the Windows side. On the Web side, I've worked with VB, ASP, JavaScript, and COM+. I've also been involved with server-side Java, which includes JSP, Servlets, and EJB, and more recently with ASP.NET/C#.

Comments and Discussions

 
GeneralMax-length and special characters Pin
_Micha7-Apr-06 5:30
_Micha7-Apr-06 5:30 
Generalthanks Pin
gemukina7-Apr-06 2:11
gemukina7-Apr-06 2:11 
GeneralThanks Pin
pgiustinoni9-Mar-06 5:47
pgiustinoni9-Mar-06 5:47 
Generalerror validating dates Pin
phil reaston18-Dec-05 16:02
phil reaston18-Dec-05 16:02 
GeneralSetting Separators for CAMSNumericEdit Pin
Thorsten Loehndorf9-Oct-05 8:53
Thorsten Loehndorf9-Oct-05 8:53 
GeneralRe: Setting Separators for CAMSNumericEdit Pin
Thorsten Loehndorf9-Oct-05 11:04
Thorsten Loehndorf9-Oct-05 11:04 
GeneralRe: Setting Separators for CAMSNumericEdit Pin
ArielR10-Sep-07 8:03
ArielR10-Sep-07 8:03 
GeneralDateEdit problem with Win98 Pin
estartu_de22-Aug-05 2:01
estartu_de22-Aug-05 2:01 
Hi!
Thank you for this great collection. Rose | [Rose]

With Windows 2000 it really works great.
But with Windows 98 SE, it is possible to enter an invalid date like 31.11.2005 (for US: 11/31/2005)

Where can I fix this? Or do I have to go trough all my code an fix it in the view-classes? Cry | :((
99% of the OS of the PCs here still is Win98. Sniff | :^)

Greets
Sonja
GeneralRe: DateEdit problem with Win98 Pin
estartu_de25-Sep-05 21:47
estartu_de25-Sep-05 21:47 
GeneralCompile Error Pin
Robert Valentino20-Aug-05 7:45
Robert Valentino20-Aug-05 7:45 
GeneralRe: Compile Error Pin
TheGreatAndPowerfulOz20-Aug-05 9:06
TheGreatAndPowerfulOz20-Aug-05 9:06 
GeneralPort to VS 2005 Pin
Spiros7-Aug-05 12:06
Spiros7-Aug-05 12:06 
GeneralRe: Port to VS 2005 Pin
Alvaro Mendez9-Aug-05 20:00
Alvaro Mendez9-Aug-05 20:00 
GeneralRe: Port to VS 2005 Pin
Spiros10-Aug-05 1:56
Spiros10-Aug-05 1:56 
GeneralRe: Port to VS 2005 Pin
AlexEvans3-Oct-08 16:44
AlexEvans3-Oct-08 16:44 
GeneralRe: Port to VS 2005 Pin
Paolo Vernazza4-Dec-05 8:22
Paolo Vernazza4-Dec-05 8:22 
GeneralRe: Port to VS 2005 Pin
mace8-Dec-05 23:33
mace8-Dec-05 23:33 
GeneralRe: Port to VS 2005 Pin
Spiros13-Dec-05 2:57
Spiros13-Dec-05 2:57 
QuestionRe: Port to VS 2005 Pin
Luckymmkay28-Aug-06 5:47
Luckymmkay28-Aug-06 5:47 
AnswerRe: Port to VS 2005 Pin
Paolo Vernazza28-Aug-06 6:22
Paolo Vernazza28-Aug-06 6:22 
GeneralRe: Port to VS 2005 Pin
Luckymmkay28-Aug-06 7:23
Luckymmkay28-Aug-06 7:23 
GeneralRe: Port to VS 2005 Pin
Greg Strauss20-Sep-06 7:27
Greg Strauss20-Sep-06 7:27 
AnswerRe: Port to VS 2005 Pin
Arshad_M27-Nov-06 6:05
Arshad_M27-Nov-06 6:05 
GeneralRe: Port to VS 2005 Pin
Mauro Leggieri2-Jul-07 15:50
Mauro Leggieri2-Jul-07 15:50 
GeneralRe: Port to VS 2005 Pin
toto66666630-Apr-08 1:41
toto66666630-Apr-08 1:41 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.