PRODUCT : Borland C++ NUMBER : 1716 VERSION : 3.X OS : WIN DATE : October 25, 1993 PAGE : 1/10 TITLE : How to Validate an Edit Control There are two possible ways of validating an edit control. The first way is to validate the input as the user types the text. The second way is to validate the input when the user is done entering the input. The techniques described here are usable as part of an Windows API program, but the sample code is provided using Object Windows Library. Validate as you go: ------------------- In order to check the user's input as he types it, you must trap the WM_CHAR message for the edit control. For every character the user types in, the window procedure for the edit control will receive a WM_CHAR message. Then it is matter of checking what the user types in against what the program is looking for. If you're using C/API to do Windows programming, you must subclass the edit control using the SetWindowsLong() function. You will need to provide another window procedure and check the message. If it is a WM_CHAR, then you will do your special processing. If it isn't a WM_CHAR, then you can pass the message to the old window procedure by using CallWindowProc(). For more information about subclassing, take a look at chapter 2 of Jeffrey Richter's _Windows 3.1: A Developer's Guide_. If you're using OWL the idea is similar. Instead of providing window procedure, you need to derive a new class from TEdit and provide a DDVT for WM_CHAR. Instead of using CallWindowProc to pass the message on to the old window procedure, there's a member function of TWindowsObject called DefWndProc(). If you want to "swallow" the keystroke, don't do anything in the DDVT for WM_CHAR. By trapping WM_CHAR it is also possible to provide a picture field. See the sample source code for more information. Validate When The User Finishes Typing -------------------------------------- Validating when the user finishes typing cannot be done at the edit control level. It must be done at the parent level instead. Luckily, whenever the edit control does anything, it notifies PRODUCT : Borland C++ NUMBER : 1716 VERSION : 3.X OS : WIN DATE : October 25, 1993 PAGE : 2/10 TITLE : How to Validate an Edit Control the parent via the EN_xxxx notification messages. When the user is typing into an edit control, the edit control gains focus. And when the user finishes typing, the user will try to move the focus elsewhere. During this time, an EN_KILLFOCUS will be sent from the edit control to the parent window's window procedure. This is the perfect time to read the edit control's contents and validating it against a range or format. If it is in the right format, then continue. Otherwise, set the focus back to the edit control. If the parent window is a dialog, do NOT call SetFocus(). If you do, the dialog manager will be confused and your program's behavior will change radically (the focus rectangle is on one control while the real focus is on another). Instead, use the windows message WM_NEXTDLGCTL. Send the message to the dialog to tell the dialog manager where to put the focus. If the parent window is a window, then you can use SetFocus(). You can also trap EN_SETFOCUS to provide context sensitive help for the edit controls. See the sample code for more information. Here's a sample program that does both forms of validation: # # makefile # .autodepend ROOT = Validate OBJ = valdlg.obj app.obj LIB = tclassl.lib owlwl.lib CC = bcc -H=$(ROOT).pch -ml -WS -w -v .c.obj: $(CC) -c {$< } .cpp.obj: $(CC) -c {$< } $(ROOT).exe: $(ROOT).res $(ROOT).def $(OBJ) tlink /m /s /c /C /v @&&! c0wl $(OBJ) $(ROOT).exe import.lib $(LIB) mathwl.lib cwl.lib PRODUCT : Borland C++ NUMBER : 1716 VERSION : 3.X OS : WIN DATE : October 25, 1993 PAGE : 3/10 TITLE : How to Validate an Edit Control $(ROOT).def ! rc $(ROOT).res $(ROOT).exe buildsym $(ROOT).exe $(ROOT).obj: $(ROOT).cpp $(ROOT).res: $(ROOT).rc brc -R -FO $(ROOT).res $(ROOT).rc // --------------------------------------------------------------- // // validate.rh // // --------------------------------------------------------------- // #define ID_STATUS 200 #define ID_SSN 201 #define ID_PHONE 202 // --------------------------------------------------------------- // // validate.rc // // --------------------------------------------------------------- // #include "Validate.rh" ValidateDlg DIALOG 18, 18, 142, 126 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION CLASS "ValidateClass" CAPTION "Validate" BEGIN LTEXT "Enter Social Security Number:", -1, 8, 6, 126, 8, WS_CHILD | WS_VISIBLE | WS_GROUP EDITTEXT ID_SSN, 8, 18, 126, 18, ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP PRODUCT : Borland C++ NUMBER : 1716 VERSION : 3.X OS : WIN DATE : October 25, 1993 PAGE : 4/10 TITLE : How to Validate an Edit Control LTEXT "Enter Phone Number:", -1, 8, 52, 126, 10, WS_CHILD | WS_VISIBLE | WS_GROUP EDITTEXT ID_PHONE, 8, 66, 126, 18, ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP DEFPUSHBUTTON "&Ok", IDOK, 60, 95, 24, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP CONTROL "", ID_STATUS, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER, 0, 114, 142, 12 END // --------------------------------------------------------------- // // validate.h // // --------------------------------------------------------------- // #ifndef Validate_h #define Validate_h 1 #define STRICT #define WIN31 #include #include #include #include #include "Validate.rh" #define lpszAPPSTR "Validate" #define lpszCLASSNAME "ValidateClass" #define lpszTITLE "Validate Window" class TValidateApplication : public TApplication { public: TValidateApplication(LPSTR lpszName, HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow); virtual void InitMainWindow(); }; PRODUCT : Borland C++ NUMBER : 1716 VERSION : 3.X OS : WIN DATE : October 25, 1993 PAGE : 5/10 TITLE : How to Validate an Edit Control class TMyEdit : public TEdit { protected: char *Mask; public: TMyEdit(PTWindowsObject pwParent, int resId, char *mask, PTModule pmModule = NULL); TMyEdit(PTWindowsObject pwParent, int resId, WORD textLen, PTModule pmModule = NULL); ~TMyEdit(); virtual void WmChar(RTMessage Msg) = [WM_FIRST + WM_CHAR]; }; class TValidateDialog : public TDialog { protected: TMyEdit *SSN; TMyEdit *Phone; TStatic *Status; public: TValidateDialog(PTWindowsObject pwParent, LPSTR resId, PTModule pmModule = NULL); virtual LPSTR GetClassName(); virtual void GetWindowClass(WNDCLASS&); virtual void IdSSN(RTMessage) = [ID_FIRST + ID_SSN]; virtual void IdPHONE(RTMessage) = [ID_FIRST + ID_PHONE]; }; #endif // *************************************************************** // // Filename: app.cpp // // // // Date: Oct 10, 1993 // // *************************************************************** // PRODUCT : Borland C++ NUMBER : 1716 VERSION : 3.X OS : WIN DATE : October 25, 1993 PAGE : 6/10 TITLE : How to Validate an Edit Control #include "Validate.h" int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { TValidateApplication Validate(lpszAPPSTR, hInstance, hPrevInstance, lpszCmdLine, nCmdShow); Validate.Run(); return Validate.Status; } TValidateApplication::TValidateApplication(LPSTR lpszName, HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) : TApplication(lpszName, hInstance, hPrevInstance, lpszCmdLine, nCmdShow) { /* initialization */ } void TValidateApplication::InitMainWindow() { MainWindow = new TValidateDialog(NULL, "ValidateDlg", NULL); } // *************************************************************** // // Filename: valdlg.cpp // // // // Date: Oct 10, 1993 // // *************************************************************** // #include "Validate.h" #include "ctype.h" TValidateDialog::TValidateDialog( PTWindowsObject pwParent, LPSTR resId, PTModule pmModule) : PRODUCT : Borland C++ NUMBER : 1716 VERSION : 3.X OS : WIN DATE : October 25, 1993 PAGE : 7/10 TITLE : How to Validate an Edit Control TDialog(pwParent, resId, pmModule) { SSN = new TMyEdit(this, ID_SSN, "###-##-####"); Phone = new TMyEdit(this, ID_PHONE, "(###) ###-####"); Status = new TStatic(this, ID_STATUS, 99); } LPSTR TValidateDialog::GetClassName() { return lpszCLASSNAME; } void TValidateDialog::GetWindowClass(WNDCLASS& wc) { TDialog::GetWindowClass(wc); } void TValidateDialog::IdSSN(RTMessage Msg) { switch (Msg.LP.Hi) { case EN_SETFOCUS: Status->SetText("In the form of ###-##-####"); break; } DefWndProc(Msg); } void TValidateDialog::IdPHONE(RTMessage Msg) { switch (Msg.LP.Hi) { case EN_SETFOCUS: Status->SetText("In the form of (###) ###-####"); break; case EN_KILLFOCUS: { char buffer[255]; Phone->GetText(buffer, 255); if (buffer[2] != '0' && buffer[2] != '1') { // check if 2 digit of area code is not 0 or 1 PostMessage(HWindow, WM_NEXTDLGCTL, PRODUCT : Borland C++ NUMBER : 1716 VERSION : 3.X OS : WIN DATE : October 25, 1993 PAGE : 8/10 TITLE : How to Validate an Edit Control (WPARAM)Phone->HWindow, TRUE); } else if (buffer[6] == '0' || buffer[6] == '1') { // check if beginning of phone is 0 or 1 PostMessage(HWindow, WM_NEXTDLGCTL, (WPARAM)Phone->HWindow, TRUE); } } break; } DefWndProc(Msg); } // --------------------------------------------------------------- // // TMyEdit // // --------------------------------------------------------------- // TMyEdit::TMyEdit(PTWindowsObject pwParent, int resId, WORD textLen, PTModule pmModule) : TEdit(pwParent, resId, textLen, pmModule) { Mask = NULL; } TMyEdit::TMyEdit(PTWindowsObject pwParent, int resId, char *mask, PTModule pmModule) : TEdit(pwParent, resId, lstrlen(mask)+1, pmModule) { Mask = new char[lstrlen(mask) + 1]; lstrcpy(Mask, mask); } TMyEdit::~TMyEdit() { delete Mask; } PRODUCT : Borland C++ NUMBER : 1716 VERSION : 3.X OS : WIN DATE : October 25, 1993 PAGE : 9/10 TITLE : How to Validate an Edit Control void TMyEdit::WmChar(RTMessage Msg) { int begPos, endPos; // look for special keys if (Msg.WParam == VK_TAB || Msg.WParam == VK_RETURN || Msg.WParam == VK_BACK || Msg.WParam == VK_PRIOR || Msg.WParam == VK_END || Msg.WParam == VK_HOME || Msg.WParam == VK_LEFT || Msg.WParam == VK_RIGHT || Msg.WParam == VK_UP || Msg.WParam == VK_DOWN ) { DefWndProc(Msg); return; } // look for mask if (Mask) { GetSelection(begPos, endPos); switch (Mask[begPos]) { case '9': case '#': if (isdigit(Msg.WParam)) DefWndProc(Msg); break; case 'A': if (isalpha(Msg.WParam)) DefWndProc(Msg); break; default: if (Msg.WParam == Mask[begPos]) DefWndProc(Msg); } } else DefWndProc(Msg); PRODUCT : Borland C++ NUMBER : 1716 VERSION : 3.X OS : WIN DATE : October 25, 1993 PAGE : 10/10 TITLE : How to Validate an Edit Control } ;Validate.def NAME Validate EXETYPE WINDOWS DESCRIPTION 'Validate OWL Program' CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD MOVEABLE MULTIPLE HEAPSIZE 1024 STACKSIZE 8192 DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.