Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Validating Window Controls by Subclassing

0.00/5 (No votes)
3 May 2014 1  
Direct Win32 API window controls that support validation (no MFC)

Introduction

A user "AlwaysLearningNewStuff" was trying to create a window control that validates number entry.

The usual way this is done is by writing either a dialog or window handler dealing with all the validation and while it works, there is little opportunity to reuse code.

I discussed subclassing controls and he had already obviously attempted it but found it difficult. This tip is an attempt to answer the how to make a validating number entry control generally and lay the foundation for a whole range of validating controls. A word of warning to the novice programmer... the bottom subclass code is not for the faint hearted, the ease of use of the code is however very easy.

I have created the actual validating control windows in a "C" file rather than a "C++" file because I use the controls on an embedded system which will be the subject of a future article. If you feel like converting the code to a C++ class, there are plenty of hints in the discussion and code. The private data structures would become internal class data and the interface routines would become class specific functions.

The upshot of that is the strange comments around the usual #include to bring a C file into a C++ main and there is nothing tricky beyond that. If it really annoys you, rename the .c file a .cpp and be done with it.

extern "C" {
    #include "ValCtrls.h" // include our fancy validating controls
} 

Background

So what is the basic idea behind a validating control class? At its most basic, the control should not accept anything that isn't valid or warn the user something isn't valid. Many windows dialogs have a hideous behaviour that the user is expected to enter a series of data and when they click on the OK or confirm button, only then does the error actually get reported.

The most classic of these is edit entry boxes provided to enter real numbers and the user types in letters or other trash characters. The other usual thing is a valid number is typed in but it is outside a given range or valid value. So what would be useful is a control that only allowed number entry and displayed any range error as soon as the number is entered.

So on an example that we wanted an entry box that accepted numbers between 0-1000 for example, we would like these behaviours.

Word of warning: The controls while they are in error will not allow focus to be dropped from them until you fix the entry error. This includes any other standard windows controls, button, forms, etc. The one exception that has been allowed is a dialog box that can be canceled while they are in error.

IF THE CONTROL IS IN ERROR (RED), YOU HAVE TO FIX THE ENTRY ERROR YOU CAN'T MOVE FOCUS THAT IS THE WHOLE POINT OF VALIDATION.

The Esc key plays a special role. It will return the last valid entry typed. So if you start typing or are in error, a simple press off the escape key will return the last valid entry.

Extending the concept out, I added a validating combo box and buttons to show how the idea can be extended.

Using the Code

Using the controls is extremely easy. The key to validating is providing a suitable validation routine and all validation routines must be in the format.

 typedef BOOL VALIDATEPROC (HWND hWnd);

A typical validation function in the code looks like this:

/* Validate width range 0-1000 */
BOOL CheckWidth (HWND Wnd){
    CFLOAT x;
    x = GetNumber(Wnd);
    if (( x >= (CFLOAT)0.0) && (x <= (CFLOAT)1000.0)) return (TRUE);
        else return (FALSE);
};

It is completely fine if you want to use the controls but have them not validate to simply provide a value of NULL or 0 for the validate function. The sample indeed provides the same two set of number inputs, one validating one not to show this behaviour.

The controls will also correctly work and display in both a Dialog (modal or modeless) and a standard windows frame. I added in some fancy stuff just for fun and visuals like the static transparent colored text for use in labels, etc.

A word on the use of the term CFLOAT. As I explained, I use these controls on an embedded system and so often I require real numbers to be actual floats rather than doubles. CFLOAT is a simple #define at the top of "valctrls.h" file to decide which form the controls use and it is defaulted to double as the default in the sample. For novice programmers, anywhere you see the word CFLOAT you can simply think in your head that is says double.

So let's look at how we create a number entry and it is remarkably similar to how you create a normal window for obvious reason. It really is no harder and remember the usual rule if you don't need an input value then simply set it to 0 or NULL as appropriate.

/*--------------------------------------------------------------------------
 This will create and subclass a number entry box that has (lp) left places
 and (dp) decimal places. The initial value is set on string (iv)
 --------------------------------------------------------------------------*/
HWND CreateNumberEdit (HWND parent,           // Parent window to insert this control in
                       int x, int y,          // x,y co-ordinate of parent for the insert
                       int cx, int cy,        // Width and Height of the control
                       long exstyle,          // And special control exstyles (0 = unused)
                       int id,                // Id of the control (0 = unused)
                       unsigned short lp,     // Left decimal places of the largest number
                       unsigned short dp,     // Decimal places available to enter
                       CFLOAT iv,             // Initial CFLOAT value to set
                       VALIDATEPROC* proc,    // Validation procedure (0 = not used)
                       HFONT hFont,           // Handle to any special font (0 = default)
                       COLORREF selectcolor); // Color of background when selected    

The test application simply inserts the controls into a test dialog or test window and you should see the following outputs:

Points of Interest

What I hope was illustrated was that creating new UI controls and functionality does not require elaborate frameworks and in many cases the frameworks simply slow the controls down or get in the way of desired behaviour.

History

  • Version 1.0 Initial release

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here