Textbox that only accepts numbers?

Hey everyone, I've been scripting in flash and unrealscript for a while now, and I figured it was time to move up to C++. I have learned most of what I need in c++ at this point so I have started working on my first win32 program.

Right now I am just trying to make a basic calculator. Does anyone know how to make a textbox that only accepts numbers? Also, how would I multiply the values in
2 textboxes?

Also I've noticed that good win32 tutorials are kinda hard to find, anyone got any suggestions on where to find more info? I checked out MSDN but its terribly hard to follow. Any help at all would be greatly appreciated, thanks in advance.
A good win32 tutorial is the one by theForger, at "http://www.winprog.org/tutorial/". For making textboxes which only take numbers, try specifying the ES_NUMBER style for the textbox.

To multiply together the values in 2 textboxes, you could do it like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int multiply(HWND hwndParent) {
    bool bSuccess;         // variable for checking success
    int nTempA, nTempB;    // to store the numbers temporarily

    tempA = GetDlgItemInt(hwndParent, IDC_NUM1, &bSuccess, FALSE); // Get the number from IDC_NUM1
    if (bSuccess == FALSE) {    // If couldn't get value....
        MessageBox(hwndParent, "Could not get first number!", "Error", MB_OK | MB_ICONERROR);
        return 0;    // return an arbitrary number
    }
    
    tempB = GetDlgItemInt(hwndParent, IDC_NUM2, &bSuccess, FALSE); // Get the number from IDC_NUM2
    if (bSuccess == FALSE) {    // If couldn't get value....
        MessageBox(hwndParent, "Could not get second number!", "Error", MB_OK | MB_ICONERROR);
        return 0;    // return an arbitrary number
    }

    return (tempA * tempB);    // return the product of the two numbers
}


By the way, substitute IDC_NUM1 and IDC_NUM2 with the names of the edit boxes that you put in (or your resource editor generated for you).
Hey, thanks for the reply. I figured out the ES_NUMBER style a little while ago, but your code for retrieving and comparing the numbers worked great . I really appreciate your help:)
The third parameter of GetDlgItemInt is a BOOL* not a bool*

As you are passing the address of a variable, you should use the correct type so it has the correct size. Use BOOL bSuccess;

Esp. as you then go on to compare a bool against FALSE, when bool values are true and false.

Andy
Last edited on
You might want to consider an alternative approach to ES_NUMBER

The problem with ES_NUMBER style Edit controls is that they don't allow negative numbers, and that you can still paste any old string into them.

A more general approach uses subclassing. This allows you to validate the string that's being entered, including when it's being pasted in. But this can be a bit involved, so it can be easier to check the string after it's being pasted in (by responding to the EN_CHANGE message.)

The advantage of the subclass approach is that it can deal with hexadecimal numbers, negative integers, real numbers, or whatever you want.

1. You need a global for the orignal WndProc for the Edit control, plus I keep the HWND.

1
2
HWND    g_hwndEdit        = NULL;
WNDPROC g_pfnEditProc_Old = NULL;


2. Then you need to subclass the edit control in either WM_CREATE, after you create the control window, or in WM_INIDIALOG, in which case you obtain the HWND using GetDlgItem

g_pfnEditProc_Old = (WNDPROC)SetWindowLongPtr(g_hwndEdit, GWLP_WNDPROC, (LONG_PTR)MyEditProc);

3. In WM_DESTOY you should unsubclass the control

SetWindowLongPtr(g_hwndEdit, GWLP_WNDPROC, (LONG_PTR)g_pfnEditProc_Old);

4. And you need to provide the subclass proceedure (plus a forward declaration.)

5. And the handling of the paste, which proved more involved than I expected at the offset...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
void HandlePaste(HWND hWnd);

LRESULT CALLBACK
MyEditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if(uMsg == WM_CHAR)
    {
        if(0x8000 & GetKeyState(VK_CONTROL))
        {
            switch(wParam)
            {
                case 0x16: // ctrl-V
                {
                    HandlePaste(hWnd);
                    return 0;
                }
                break;

                case 0x03: // ctrl-C
                case 0x18: // ctrl-X
                {
                    // allow through
                }
                break;

                default:
                {
                    return 0;
                }
            }
        }
        else
        {
            // Only check non-digits
            if(!isdigit(wParam))
            {
                switch(wParam)
                {
                    case _T('-'):
                    {
                        DWORD from = 0;
                        DWORD to   = 0;
                        SendMessage(hWnd, EM_GETSEL, (WPARAM)&from, (WPARAM)&to);
                        if(0 == from)
                        {
                            // if to is greater than zero, we're replacing the 0th
                            // char so we don't need to worry. If we're inserting
                            // have to check the first char isn't already a -
                            if(0 == to)
                            {
                                TCHAR buffer[2] = _T(""); // big enough for one char plus term null
                                SendMessage(hWnd, WM_GETTEXT, (WPARAM)2, (WPARAM)buffer);
                                if(buffer[0] == _T('-'))
                                    return 0;
                            }
                            // allow through
                        }
                        else
                        {
                            return 0;
                        }
                    }
                    break;

                    case VK_BACK:
                    {
                        // allow backspace through
                    }
                    break;

                    default:
                    {
                        // block everything else
                        return 0;
                    }
                }
            }
        }
    }

    // call through to original WndProc for Edit control
    return CallWindowProc(g_pfnHexEditProc_Old, hWnd, uMsg, wParam, lParam);
}

bool IsValidNumber(const char* pszText, bool allowMinus)
{
    if(allowMinus && ('-' == *pszText))
        ++pszText;
    while(*pszText != '\0')
    {
        if(!isdigit(*pszText))
            return false;
        ++pszText;
    }
    return true;
}

void HandlePaste(HWND hWnd)
{
    bool isValidNumber = false;

    if(OpenClipboard(hWnd))
    {
        HANDLE hData = GetClipboardData(CF_TEXT);
        if(NULL != hData)
        {
            LPSTR pszText = (LPSTR)GlobalLock(hData);

            if(NULL != pszText)
            {
                bool doPaste      = true;
                bool allowMinus = true;

                DWORD from = 0;
                DWORD to   = 0;
                SendMessageA(hWnd, EM_GETSEL, (WPARAM)&from, (WPARAM)&to);
                if(0 == from)
                {
                    if(0 == to)
                    {
                        char buffer[2] = ""; // big enough for one char plus term null
                        SendMessageA(hWnd, WM_GETTEXT, (WPARAM)2, (WPARAM)buffer);
                        if(buffer[0] == '-')
                            doPaste = false;
                    }
                }
                else
                {
                    allowMinus = false;
                }

                if(doPaste)
                {
                    doPaste = IsValidNumber(pszText, allowMinus);
                }

                if(doPaste)
                {
                    SendMessageA(hWnd, EM_REPLACESEL, (WPARAM)TRUE, (WPARAM)pszText);
                }
            }

            GlobalUnlock(hData);
        }

        CloseClipboard();
    }
}
Last edited on
Topic archived. No new replies allowed.