Numeric Entry in an EditBox

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

Thanks, Josep, for spending time on this. Yes, that is the "logic" behind the mess. I was aware of the awkward concept of "a LONG_PTR is not a pointer", and yes, SetWindowLong is a tricky API because it eats pointers as well as scalars.

My feeling is that such strict (and confusing) type checking should not happen in a BASIC dialect. I have used such API calls since I started programming under Windows 20 years ago (before I was on an Atari ST and Motorola 68000, yet another story), and I never had a problem with the less stricter type checking of MASM. The latter throws an error if
- the parameter count is incorrect
- the size of a parameter is not correct
- you pass a DWORD instead of a REAL4 (and vice versa, of course)

Otherwise Masm assumes that you are able to read MSDN. I can't imagine that this shouldn't work with a Basic dialect. Sending a beginner in circles with monsters like PrevWinProc = CAST(ANY PTR, SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit))) is definitely not the right thing for a Beginners All purpose Symbolic Instruction Code ;-)
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: Numeric Entry in an EditBox

Post by Josep Roca »

And the headers could have been more BASIC friendly by using BYREF for OUT parameters instead of BYVAL something PTR, etc., but this is what we have and isn't going to change.
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

Josep Roca wrote:> The last para of SetWindowLongPtr is definitely a pointer - to the WndProc. Looks like a FB bug. In any case, it works, and you can ignore the warning.

It is not a FB bug. In the declare, it is defined as a LONG (32-bit) or LONG_PTR (64-bit), that is an scalar. Therefore, if you want to pass a pointer you have to cast it: SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit)). Using LONG_PTR will work both with 32 and 64 bit because LONG_PTR evaluates as a LONG when compiled with 32-bit.
It's a while ago now, but I forgot that you had posted the above. It does get rid of the warning messages.

I've read, with interest, the later discussions on scalars and pointers and the need for casting, and having come from a simpler programming background (most of which was many years ago) I found it very difficult to take in. No doubt I will in due course.

jj2007
I've been on the internet to try to find out more about subclassing and I'm afraid it's all gone completely over my head. I just can't take it in. I tried adjusting the code you provided to take into account the range of characters to be included in numeric entry and I'm sorry to say without success.

I think what it does call for is a FreeBasic tutorial on classes and sub-classes for we dummies and maybe my ever aging brain cells will take it in.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: Numeric Entry in an EditBox

Post by Josep Roca »

There is not need of a tutorial for something so simple.

Code: Select all

SetWindowSubclass hCtl, CAST(SUBCLASSPROC, @MySubclassProc), uIdSubclass, dwRefData
Where hCtl is the handle of the control to subclass, uIdSubclass and identidier, e.g. 1, and dwRefData a pointer to reference data (can be NULL).

Code: Select all

' ========================================================================================
' Processes messages for the subclassed Button window.
' ========================================================================================
FUNCTION MySubclassProc ( _
   BYVAL hwnd   AS HWND, _                 ' // Control window handle
   BYVAL uMsg   AS UINT, _                 ' // Type of message
   BYVAL wParam AS WPARAM, _               ' // First message parameter
   BYVAL lParam AS LPARAM, _               ' // Second message parameter
   BYVAL uIdSubclass AS UINT_PTR, _        ' // The subclass ID
   BYVAL dwRefData AS DWORD_PTR _          ' // Pointer to reference data
   ) AS LRESULT

   SELECT CASE uMsg

      CASE WM_GETDLGCODE
         ' // All keyboard input
         FUNCTION = DLGC_WANTALLKEYS
         EXIT FUNCTION

      ' // ToDo: Process Windows messages
      CASE WM_KEYDOWN
         ' ...
         ' ...
         EXIT FUNCTION

      CASE WM_DESTROY
         ' // REQUIRED: Remove control subclassing
         RemoveWindowSubclass hwnd, @Button_SubclassProc, uIdSubclass

   END SELECT

   ' // Default processing of Windows messages
   FUNCTION = DefSubclassProc(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================
MSDN documentation:

SetWindowSubclass : https://docs.microsoft.com/en-us/window ... owsubclass

Subclassing Controls: https://docs.microsoft.com/en-us/window ... g-overview
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

Josep Roca wrote:There is not need of a tutorial for something so simple.

Code: Select all

SetWindowSubclass hCtl, CAST(SUBCLASSPROC, @MySubclassProc), uIdSubclass, dwRefData
Where hCtl is the handle of the control to subclass, uIdSubclass and identidier, e.g. 1, and dwRefData a pointer to reference data (can be NULL).

Code: Select all

' ========================================================================================
' Processes messages for the subclassed Button window.
' ========================================================================================
FUNCTION MySubclassProc ( _
   BYVAL hwnd   AS HWND, _                 ' // Control window handle
   BYVAL uMsg   AS UINT, _                 ' // Type of message
   BYVAL wParam AS WPARAM, _               ' // First message parameter
   BYVAL lParam AS LPARAM, _               ' // Second message parameter
   BYVAL uIdSubclass AS UINT_PTR, _        ' // The subclass ID
   BYVAL dwRefData AS DWORD_PTR _          ' // Pointer to reference data
   ) AS LRESULT

   SELECT CASE uMsg

      CASE WM_GETDLGCODE
         ' // All keyboard input
         FUNCTION = DLGC_WANTALLKEYS
         EXIT FUNCTION

      ' // ToDo: Process Windows messages
      CASE WM_KEYDOWN
         ' ...
         ' ...
         EXIT FUNCTION

      CASE WM_DESTROY
         ' // REQUIRED: Remove control subclassing
         RemoveWindowSubclass hwnd, @Button_SubclassProc, uIdSubclass

   END SELECT

   ' // Default processing of Windows messages
   FUNCTION = DefSubclassProc(hwnd, uMsg, wParam, lParam)

END FUNCTION
' ========================================================================================
MSDN documentation:

SetWindowSubclass : https://docs.microsoft.com/en-us/window ... owsubclass

Subclassing Controls: https://docs.microsoft.com/en-us/window ... g-overview
Josep
You are far far more proficient at coding than I am and what is clear and simple to you is, unfortunately, not to me. A tutorial with lots of examples would be very useful to knock it into me. For instance with the code that jj2007 provided, which he based on my code, he inserted a subclass and this did a check for characters greater than ASCII 57. I have tried to extend this to check for admissable characters with absolutely no success and because I don't understand the subclassing I don't know what I am doing wrong. I will continue trying but it is like working in a fog.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

RNBW wrote:... ASCII 57. I have tried to extend this to check for admissable characters with absolutely no success and because I don't understand the subclassing I don't know what I am doing wrong.
If you post your code, I can look at it this evening. It's probably a minor issue.

All you have to do is:
- read the current text into a local buffer (WM_GETTEXT...)
- get the current cursor position inside the edit control (EM_GETSEL)
- decide if the char passed is admissible at this position; if not, set wp2 to zero to block it.
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

jj2007 wrote:
RNBW wrote:... ASCII 57. I have tried to extend this to check for admissable characters with absolutely no success and because I don't understand the subclassing I don't know what I am doing wrong.
If you post your code, I can look at it this evening. It's probably a minor issue.

All you have to do is:
- read the current text into a local buffer (WM_GETTEXT...)
- get the current cursor position inside the edit control (EM_GETSEL)
- decide if the char passed is admissible at this position; if not, set wp2 to zero to block it.
The code is similar to that you posted for me earlier, but I have extended the wparam check.

Code: Select all

REM=============================================
'  NUMERIC INPUT IN A TEXTBOX
'  NumericInputInTextBox_03.bas
'  This does a check for 0-9 and - or . and prevents entry of all other
'  characters.   It ensures that "-" can only be placed at the start of
'  the number entry.  It also ensures that only one "." or "-"   can be
'  entered.
'  Characters entered are right justified
'  Code by RNBW. 
'============================================

#INCLUDE "WinGUI.bi"
#include "string.bi"

DIM shared AS HWND Window_Main, Button_Ok, Edit_1,Edit_2
DIM shared AS MSG msg
DIM shared AS STRING sTxt, oldsTxt
DIM shared AS INTEGER pos0
dim shared as double numb
Dim shared as any ptr PrevWinProc

FUNCTION sNum(BYVAL sTxt AS STRING) AS STRING
   'Function to check that character input is 0-9, - or .
   
   DIM AS STRING sNum1
   DIM AS INTEGER i, a, t
                                             
   FOR i = 1 TO LEN(sTxt)
      a = ASC(MID(sTxt,i,1))
      IF a = 46 THEN t = t + 1
        IF (a = 46) AND (t > 1) THEN a = 0    'only DOT after FIRST is cleared
        IF a = 45 AND i>1 THEN a = 0          'so really almost anything do, not just 8
        'IF a = 46 AND i = 1 THEN sNum1 = "0" + sNum1
      IF a = 45 OR a = 46 OR a > 47 AND a < 58 THEN sNum1 = sNum1 + CHR(a)
   NEXT
   
   'a=ASC(MID(sTxt,1,1))
    'IF a = 45 AND MID(sTxt,2,1) = "." THEN sNum1 = "-0" + sNum1
   
   RETURN sNum1

END FUNCTION

Sub SubEdit(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
  Dim as WPARAM wp2
  wp2=wParam
  if uMsg=WM_CHAR then
   print wParam; " ";
   if wParam <45 or wParam = 47 or wParam>57 then wp2=0: print wParam;"? ";
  endif
  CallWindowProc(PrevWinProc, hWnd, uMsg, wp2, lParam)
End Sub

'Create a window with an Editbox and a button:
Window_Main = Window_New(50, 100, 300, 200, "Numeric Entry Filter!")
VAR Label_sTxt = Label_New(10, 10, 150, 20, "Enter numbers:",, Window_Main)
Var label_2 =  Label_New(10, 40, 150, 20, "Number to 3 dec",, Window_Main)
Edit_1 = EditBox_New(150, 10, 100, 20, "",ES_RIGHT or WS_BORDER, Window_Main)
PrevWinProc = CAST(ANY PTR, SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit)))

Edit_2 = EditBox_New(150, 40, 100, 20, "",ES_RIGHT or ES_READONLY or WS_BORDER, Window_Main)
Button_Ok = Button_New(160, 100, 60, 20, "Ok",, Window_Main)


'Set timer to 300 miliseconds:
SETTIMER(Window_Main, 0, 100, 0 )

DO
   WaitEvent(Window_Main,msg)
   SELECT CASE msg.message
      CASE WM_TIMER+999
         'Check contents of the edit box every 300 millisecinds
         sTxt = EditBox_GetText(Edit_1)   'get text from edit box
         oldsTxt = sTxt      'make text the oldtext
         sTxt = sNum(sTxt)  'gets new text from function sNum(sTxt) which does the checking
         IF oldsTxt <> sTxt THEN
            EditBox_SetText(Edit_1, sTxt)   'if old text is not the same as the new text then use new text
            pos0 = LEN(sTxt)   'position of character is the length of the current text
            SENDMESSAGE(Edit_1, EM_SETSEL, pos0, pos0)
         END IF
      CASE WM_LBUTTONDOWN
         sTxt = EditBox_GetText(Edit_1)
         numb = val(sTxt)
         sTxt = format(numb, "####0.000")
         EditBox_SetText(Edit_2,sTxt)
   END SELECT
LOOP UNTIL Window_Event_Close(Window_Main, msg)

END
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

RNBW wrote:The code is similar to that you posted for me earlier, but I have extended the wparam check.
That was pretty close already. I've shortened it a little bit - tell me if it's OK now:

Code: Select all

REM=============================================
'  NUMERIC INPUT IN A TEXTBOX
'  NumericInputInTextBox_03.bas
'  This does a check for 0-9 and - or . and prevents entry of all other
'  characters.   It ensures that "-" can only be placed at the start of
'  the number entry.  It also ensures that only one "." or "-"   can be
'  entered.
'  Characters entered are right justified
'  Code by RNBW. 
'============================================

#INCLUDE "WinGUI.bi"
#include "string.bi"
#include "crt.bi"

DIM shared AS HWND Window_Main, Button_Ok, Edit_1,Edit_2
DIM shared AS MSG msg
DIM shared AS STRING sTxt
Dim shared as double numb
Dim shared as any ptr PrevWinProc

Sub SubEdit(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
  Dim as WPARAM wp2
  Dim txtpos as integer
  Dim num3 as double
  Dim txt as string*1000
  wp2=wParam
  if uMsg=WM_CHAR then	' user typed something
	if wParam <48 or wParam>57 then	' it's not a number (48="0", 57="9")
		SendMessage(hWnd, WM_GETTEXT, 1000, @txt)		' let's get the current text
		txtpos=SendMessage(hWnd, EM_GETSEL, 0, 0) and 127	' and the cursor position
		if wParam=47 then wp2=0			' / not allowed
		if wParam=46 and Instr(txt, ".") then wp2=0	' one dot only
		if (wParam=43 or wParam=45) and txtpos then wp2=0		' +- only in pos 0
		if wParam<>VK_BACK then
			if wParam<43 or wParam>57 then wp2=0
		endif
	endif
  endif
  CallWindowProc(PrevWinProc, hWnd, uMsg, wp2, lParam)
  if uMsg=WM_CHAR then
         sTxt = EditBox_GetText(Edit_1)
         numb = val(sTxt)
         sTxt = format(numb, "####0.000")
         EditBox_SetText(Edit_2,sTxt)
  endif
End Sub

'Create a window with an Editbox and a button:
Window_Main = Window_New(50, 100, 300, 200, "Numeric Entry Filter!")
VAR Label_sTxt = Label_New(10, 10, 150, 20, "Enter numbers:",, Window_Main)
Var label_2 =  Label_New(10, 40, 150, 20, "Number to 3 dec",, Window_Main)
Edit_1 = EditBox_New(150, 10, 100, 20, "",ES_RIGHT or WS_BORDER, Window_Main)
PrevWinProc = CAST(ANY PTR, SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit)))
Edit_2 = EditBox_New(150, 40, 100, 20, "",ES_RIGHT or ES_READONLY or WS_BORDER, Window_Main)
Button_Ok = Button_New(160, 100, 60, 20, "Ok",, Window_Main)
SetFocus(Edit_1)
DO
   WaitEvent(Window_Main,msg)
LOOP UNTIL Window_Event_Close(Window_Main, msg)
END
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

jj2007 wrote:
RNBW wrote:The code is similar to that you posted for me earlier, but I have extended the wparam check.
That was pretty close already. I've shortened it a little bit - tell me if it's OK now:

Code: Select all

REM=============================================
'  NUMERIC INPUT IN A TEXTBOX
'  NumericInputInTextBox_03.bas
'  This does a check for 0-9 and - or . and prevents entry of all other
'  characters.   It ensures that "-" can only be placed at the start of
'  the number entry.  It also ensures that only one "." or "-"   can be
'  entered.
'  Characters entered are right justified
'  Code by RNBW. 
'============================================

#INCLUDE "WinGUI.bi"
#include "string.bi"
#include "crt.bi"

DIM shared AS HWND Window_Main, Button_Ok, Edit_1,Edit_2
DIM shared AS MSG msg
DIM shared AS STRING sTxt
Dim shared as double numb
Dim shared as any ptr PrevWinProc

Sub SubEdit(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
  Dim as WPARAM wp2
  Dim txtpos as integer
  Dim num3 as double
  Dim txt as string*1000
  wp2=wParam
  if uMsg=WM_CHAR then	' user typed something
	if wParam <48 or wParam>57 then	' it's not a number (48="0", 57="9")
		SendMessage(hWnd, WM_GETTEXT, 1000, @txt)		' let's get the current text
		txtpos=SendMessage(hWnd, EM_GETSEL, 0, 0) and 127	' and the cursor position
		if wParam=47 then wp2=0			' / not allowed
		if wParam=46 and Instr(txt, ".") then wp2=0	' one dot only
		if (wParam=43 or wParam=45) and txtpos then wp2=0		' +- only in pos 0
		if wParam<>VK_BACK then
			if wParam<43 or wParam>57 then wp2=0
		endif
	endif
  endif
  CallWindowProc(PrevWinProc, hWnd, uMsg, wp2, lParam)
  if uMsg=WM_CHAR then
         sTxt = EditBox_GetText(Edit_1)
         numb = val(sTxt)
         sTxt = format(numb, "####0.000")
         EditBox_SetText(Edit_2,sTxt)
  endif
End Sub

'Create a window with an Editbox and a button:
Window_Main = Window_New(50, 100, 300, 200, "Numeric Entry Filter!")
VAR Label_sTxt = Label_New(10, 10, 150, 20, "Enter numbers:",, Window_Main)
Var label_2 =  Label_New(10, 40, 150, 20, "Number to 3 dec",, Window_Main)
Edit_1 = EditBox_New(150, 10, 100, 20, "",ES_RIGHT or WS_BORDER, Window_Main)
PrevWinProc = CAST(ANY PTR, SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit)))
Edit_2 = EditBox_New(150, 40, 100, 20, "",ES_RIGHT or ES_READONLY or WS_BORDER, Window_Main)
Button_Ok = Button_New(160, 100, 60, 20, "Ok",, Window_Main)
SetFocus(Edit_1)
DO
   WaitEvent(Window_Main,msg)
LOOP UNTIL Window_Event_Close(Window_Main, msg)
END
THAT'S DONE IT. Thank you very much.
I just needed to change

Code: Select all

SendMessage(hWnd, WM_GETTEXT, 1000, @txt)
to

Code: Select all

SendMessage(hWnd, WM_GETTEXT, 1000, cast (LONG_PTR,@txt))
to get rid of the warning message about scalars.

I'll study your code now to see exactly how it works. Your help is very much appreciated.
PaulSquires
Posts: 1002
Joined: Jul 14, 2005 23:41

Re: Numeric Entry in an EditBox

Post by PaulSquires »

SendMessage(hWnd, WM_GETTEXT, 1000, cast (LONG_PTR,@txt))
When dealing with SendMessage because the parameters are WPARAM and LPARAM, I've gotten into the habit of casting as follows (instead of LONG_PTR):

SendMessage(hWnd, WM_GETTEXT, 1000, cast (LPARAM,@txt))
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

RNBW wrote:I just needed to change

Code: Select all

SendMessage(hWnd, WM_GETTEXT, 1000, @txt)
to

Code: Select all

SendMessage(hWnd, WM_GETTEXT, 1000, cast (LONG_PTR,@txt))
to get rid of the warning message about scalars.
You can happily ignore that warning, it's a FreeBasic bug because WM_GETTEXT expects a pointer, not a scalar (Microsoft docs):

Code: Select all

lParam
A pointer to the buffer that is to receive the text
@Paul: nice workaround ;-)
Last edited by jj2007 on Aug 28, 2018 19:14, edited 1 time in total.
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

I've had a look at the code and I think I understand what has been done. I can't say that I actually understand what is going on but I can see it. I've put some additional notes in the code to help me in the future (I have the memory span of a gnat!) and I've also incorporated Paul Squires' suggestion, but retained jj2007 equivalent code as a remark. It just shows how many ways there are of doing things.

The revised code follows. I hope it's useful to someone, besides myself. Thank you again for all the help I've been given.

Code: Select all

REM=============================================
'  NUMERIC INPUT IN A TEXTBOX
'  TestSubClass_02.bas
'  This does a check for 0-9 and - or + or . and prevents entry of all other
'  characters.   It ensures that "- +" can only be placed at the start of
'  the number entry.  It also ensures that only one "." or "-"   can be
'  entered.
'  Characters entered are right justified
'  Initial Code by RNBW and subclassing modifications by jj2007
'============================================

#INCLUDE "WinGUI.bi"
#include "string.bi"
#include "crt.bi"

DIM shared AS HWND Window_Main, Button_Ok, Edit_1,Edit_2
DIM shared AS MSG msg
DIM shared AS STRING sTxt
Dim shared as double numb
Dim shared as any ptr PrevWinProc

Sub SubEdit(ByVal hWnd As HWND, ByVal uMsg As UINT, ByVal wParam As WPARAM, ByVal lParam As LPARAM)
  Dim as WPARAM wp2
  Dim txtpos as integer
  Dim num3 as double
  Dim txt as string*1000
  wp2=wParam
  if uMsg=WM_CHAR then   ' user typed something
   if wParam <48 or wParam>57 then   ' it's not a number (48="0", 57="9")
      SendMessage(hWnd, WM_GETTEXT, 1000, cast (LPARAM,@txt))    'Paul Squires' suggestion
      'SendMessage(hWnd, WM_GETTEXT, 1000, cast (LONG_PTR,@txt))      ' let's get the current text
      '                                                              text size        ptr to txt
      txtpos=SendMessage(hWnd, EM_GETSEL, 0, 0) and 127   ' and the cursor position
      '                                                                                127 is delete
      if wParam=47 then wp2=0         ' / not allowed
      if wParam=46 and Instr(txt, ".") then wp2=0   ' one dot only
      if (wParam=43 or wParam=45) and txtpos then wp2=0      ' +- only in pos 0
      if wParam<>VK_BACK then         ' wParam <> Backspace
         if wParam<43 or wParam>57 then wp2=0
      endif
   endif
  endif
  CallWindowProc(PrevWinProc, hWnd, uMsg, wp2, lParam)
  if uMsg=WM_CHAR then
         sTxt = EditBox_GetText(Edit_1)
         numb = val(sTxt)
         sTxt = format(numb, "####0.000")
         EditBox_SetText(Edit_2,sTxt)
  endif
End Sub

'Create a window with an Editbox and a button:
Window_Main = Window_New(50, 100, 300, 200, "Numeric Entry Filter!")

VAR Label_sTxt = Label_New(10, 10, 150, 20, "Enter numbers:",, Window_Main)
Var label_2 =  Label_New(10, 40, 150, 20, "Number to 3 dec",, Window_Main)

Edit_1 = EditBox_New(150, 10, 100, 20, "",ES_RIGHT or WS_BORDER, Window_Main)

PrevWinProc = CAST(ANY PTR, SetWindowLongPtr(Edit_1, GWLP_WNDPROC, CAST(LONG_PTR, @SubEdit)))

Edit_2 = EditBox_New(150, 40, 100, 20, "",ES_RIGHT or ES_READONLY or WS_BORDER, Window_Main)

'Button_Ok = Button_New(160, 100, 60, 20, "Ok",, Window_Main)          'not really needed

SetFocus(Edit_1)

DO
   WaitEvent(Window_Main,msg)
LOOP UNTIL Window_Event_Close(Window_Main, msg)
END
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

> txtpos=SendMessage(hWnd, EM_GETSEL, 0, 0) and 127
The and 127 just eliminates the HIWORD of the return value. In non-sloppy code, it would be and 65535 ;-)
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

jj2007 wrote:> txtpos=SendMessage(hWnd, EM_GETSEL, 0, 0) and 127
The and 127 just eliminates the HIWORD of the return value. In non-sloppy code, it would be and 65535 ;-)
Thank you for the explanation. Should I use 65535?
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBox

Post by jj2007 »

If you have a suspicion that a user might need more than 127 characters, use and 65535. In most cases, and 31 should be enough ;-)

Code: Select all

EM_GETSEL: The return value is a zero-based 32-bit value with the starting position of the selection in the low-order word and the position of the first character after the last selected character in the high-order word.
A little variant that limits the input to 9 chars:

Code: Select all

  if uMsg=WM_CHAR and wParam<>VK_BACK then	' user typed something
	if SendMessage(hWnd, WM_GETTEXT, 1000, @txt)>=9 then wp2=0  ' let's get the current text, and limit inputs to 9 bytes
	if wParam>57 and wParam<>101 then	' definitely not a number (57="9") - but exponent is allowed (e=101)
		wp2=0		' letters etc not allowed
	elseif wParam<48 then	' it's not a number (48="0")
		if wParam=47 then wp2=0			' / not allowed
		txtpos=SendMessage(hWnd, EM_GETSEL, 0, 0) and 15	' and the cursor position
		if wParam=46 and Instr(txt, ".") then wp2=0		' one dot only
		if (wParam=43 or wParam=45) and txtpos then wp2=0	' +- only in pos 0
		if wParam<43 or wParam=44 then wp2=0
	endif
Post Reply