Source code for C_NumberEditBox
Download
The source files for this module are listed below. You can also download the module C_NumberEditBox as a zip archive; this archive contains all the source files and documentation.
Description
CNumberEditBox allows you to transform a regular Windows edit control into a numbers-only edit box.
Information
This source code also uses our CSubclassedWindow class. You can also download it at our website.
To transform a regular Windows edit box into a numbers-only edit box, you have to create an instance of the CNumberEditBox class. To transform an edit box, initialization can be done in two ways; either pass in the window handle of the dialog it is on and the resource ID of the edit box, or pass in the edit box control's handle directly. You also have to specify the numeric upper limit that may be accepted in the edit box and the maximum number of digits to allow.
Once the edit box is set up, you can set it's value using the SetTo method. This method puts the number you specify into the edit box itself. Use the method Get to consecutively get the current value of the edit box.
There are two special 'numeric' values defined that the SetTo and Get methods use. The value cnError is returned when the Get method encounters an error when retrieving the value from the edit box itself. The value cnNoValue is returned by Get to indicate no value was entered in the edit box (an empty edit box). You can opt to have '0' returned instead by specifying this as a parameter to the Get method. The SetTo method also accepts the special value cnNoValue; it will empty the edit box.
The user is only allowed to enter the digits 0-9, and no other characters. Pasting into the edit box is also disabled. If an invalid key is pressed, or if the pressed key would generate a number that is above the pre-set upper limit, the user will receive the standard Windows error beep. This way only positive whole numbers can be entered by the user of the specified size and/or below the specified maximum value.
Notes / todo's
- Add support for pasting into the edit box.
- Add support for negative numbers.
Files
Each file belonging to this source code module is listed below.
NumberEditBox.h
/*******************************************************************************
Version: 2
Author: Carl Colijn, TwoLogs
Contact: c.colijn@twologs.com
Source: http://www.twologs.com/en/resources/sourcecode.asp
This code is freely distributable, as long as this comment remains intact.
If you find this source useful, you may use this code in your own projects
free of charge, but some acknowledgement to the author of this code is always
appreciated :)
The source is however distributed 'as is' without waranty and/or support, and
may not be fit for each and every application. Use it at your own discretion
and at your own risk.
The source already has undergone testing. This doesn't mean however that all
bugs are removed from this piece of code. If you find one of them, please
contact me about it. I can however not guarantee when and if the bug will be
fixed.
More information about this module can be found in the accompanying HTML file.
*******************************************************************************/
#ifndef INCLUDE_TWOLOGS_COMMON_NUMBEREDITBOX_H
#define INCLUDE_TWOLOGS_COMMON_NUMBEREDITBOX_H
#include "..\C_SubclassedWindow\SubclassedWindow.h"
class CNumberEditBox: private CSubclassedWindow {
public:
// Special return values
static const long cnError;
static const long cnNoValue;
// Con- & destructor
CNumberEditBox();
virtual ~CNumberEditBox();
// Initializes the edit box
void Initialize(
HWND hDlg,
DWORD nEditBoxID,
long nUpperBound,
long nMaxDigits
);
void Initialize(
HWND hControl,
long nUpperBound,
long nMaxDigits
);
// Sets the content to the given number
void SetTo(long nNumber) const;
// Gets the content
long Get(bool bNoValueIsNul = false) const;
private:
// The upper bound to use
long m_nUpperBound;
// The edit box's window handle
HWND m_hEditBox;
// Processes the given message
void ProcessMessage(CMessage& oMsg);
};
#endif // INCLUDE_TWOLOGS_COMMON_NUMBEREDITBOX_H
NumberEditBox.cpp
#include "NumberEditBox.h"
#include <string>
// Special return values
const long CNumberEditBox::cnError = (long)0xFFFFFFFF;
const long CNumberEditBox::cnNoValue = (long)0xFFFFFFFE;
// Con- & destructor
CNumberEditBox::CNumberEditBox():
m_nUpperBound(0),
m_hEditBox(NULL) {
}
CNumberEditBox::~CNumberEditBox() {
}
// Initializes the edit box
void CNumberEditBox::Initialize(
HWND hDlg,
DWORD nEditBoxID,
long nUpperBound,
long nMaxDigits) {
Initialize(GetDlgItem(hDlg, nEditBoxID), nUpperBound, nMaxDigits);
}
void CNumberEditBox::Initialize(
HWND hControl,
long nUpperBound,
long nMaxDigits) {
// Note the restraints on the edit box
m_nUpperBound = nUpperBound;
// Make us control the edit box
m_hEditBox = hControl;
Subclass(m_hEditBox);
// And apply the maximum number of digits to allow
SendMessage(m_hEditBox, EM_LIMITTEXT, nMaxDigits + 1, 0);
}
// Sets the content to the given number
void CNumberEditBox::SetTo(long nNumber) const {
char sNumber[30];
if (nNumber == cnNoValue) {
sNumber[0] = '\0';
} else {
ltoa(nNumber, sNumber, 10);
}
SetWindowText(m_hEditBox, sNumber);
}
// Gets the content
long CNumberEditBox::Get(bool bNoValueIsNul) const {
// Get the textual representation
bool bRetrieving = true;
bool bSuccess = true;
std::string sNumber;
DWORD nTextSize = 256;
do {
// Make room for the current size
sNumber.resize(nTextSize + 1);
// Get the text
DWORD nRetrievedSize = GetWindowText(
m_hEditBox,
const_cast<char*>(sNumber.c_str()),
nTextSize
);
if (nRetrievedSize == 0) {
// Possible error -> check
bSuccess = GetLastError() == 0;
bRetrieving = false;
sNumber = "";
} else if (nRetrievedSize == nTextSize) {
// Possible truncation -> enlarge
nTextSize = nTextSize * 2;
} else {
// Done -> truncate the content to the correct size
sNumber.resize(nRetrievedSize);
// And exit retrieving
bRetrieving = false;
}
} while (bRetrieving && bSuccess);
// Look if successfull
long nNumber;
if (bSuccess) {
// Yes -> extract the number from the text
if (sNumber.size() == 0) {
if (bNoValueIsNul) {
nNumber = 0;
} else {
nNumber = cnNoValue;
}
} else {
nNumber = atol(sNumber.c_str());
}
} else {
// No -> note
nNumber = cnError;
}
// And return the number
return nNumber;
}
// Processes the given message
void CNumberEditBox::ProcessMessage(CMessage& oMsg) {
// Look if it's a char message
oMsg.bStop = false;
if (oMsg.eCode == WM_CHAR) {
// Yes -> look what char is pressed
switch (oMsg.nWParam) {
case 0x30: // 0
case 0x31: // 1
case 0x32: // 2
case 0x33: // 3
case 0x34: // 4
case 0x35: // 5
case 0x36: // 6
case 0x37: // 7
case 0x38: // 8
case 0x39: { // 9
// Numeric, but possibly invalid end result -> get the existing value
char sBuffer[30];
int nResult = GetWindowText(m_hEditBox, sBuffer, 29);
std::string sOldValue = nResult == 0? "": sBuffer;
// Look where this char will be entered
DWORD nSelStart;
DWORD nSelEnd;
SendMessage(m_hEditBox, EM_GETSEL, (WPARAM)&nSelStart, (LPARAM)&nSelEnd);
// Replicate what would happen if this digit was entered
if (nSelEnd > nSelStart) {
sOldValue.erase(
sOldValue.begin() + nSelStart,
sOldValue.begin() + nSelEnd
);
}
char sNewDigit[2];
sNewDigit[0] = oMsg.nWParam;
sNewDigit[1] = '\0';
sOldValue.insert(nSelStart, sNewDigit);
// And determine if the new digit is allowed
int nNewValue = atol(sOldValue.c_str());
oMsg.bStop = nNewValue > m_nUpperBound;
break;
}
case 3: // Ctrl-C
case 24: // Ctrl-X
case 26: // Ctrl-Z
case VK_END: // End
case VK_HOME: // Home
case VK_PRIOR: // Page up
case VK_NEXT: // Page down
case VK_LEFT: // Cursor left
case VK_UP: // Cursor up
case VK_RIGHT: // Cursor right
case VK_DOWN: // Cursor down
case VK_INSERT: // Insert
case VK_BACK: // Backspace
case VK_DELETE: { // Delete
// Valid key -> pass through
break;
}
default: {
// Key not allowed -> do not pass
oMsg.bStop = true;
break;
}
}
}
// And look if to allow the message
if (oMsg.bStop) {
// No -> notify the user
MessageBeep(MB_ICONEXCLAMATION);
}
}

Products
Overview
C_NumberEditBox