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
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

That could be useful to limit the characters in a textbox.
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

RNBW wrote: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
I have found that, when editing, it is possible to have both "+" and "-" at the beginning of the numeric entry. Since this is not acceptable, I have amended the code to exclude the "+" because by default the number is positive.

The revised code is below, where it can be seen that I have REMd the old code:

Code: Select all

REM=============================================
'  NUMERIC INPUT IN A TEXTBOX
'  TestSubClass_03.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
      '                                                                                
      if wParam=47 then wp2=0         ' / not allowed
      if wParam=46 and Instr(txt, ".") then wp2=0   ' one dot only
      REM if (wParam=43 or wParam=45) and txtpos then wp2=0      ' +- only in pos 0
      if wParam=45 and txtpos then wp2=0      ' +- only in pos 0
      if wParam<>VK_BACK then         ' wParam <> Backspace
         REM if wParam<43 or wParam>57 then wp2=0
         if wParam<45 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
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBoxLothar

Post by RNBW »

The following is an example of filtered numeric entry into a StringGadget (textbox) using subclassing and FBGUI Library for Windows 2. It is a replica of that for Lothar Schirm's Simple WinAPI Library in the last post.

Code: Select all

'================================
'   NUMERIC INPUT INTO A STRINGGADGET
'   Uses: FBGUI Library for Windows 2
'   NumericInputIntoStringGadget_03.bas
'----------------------------------------------------
'  The input excludes all characters except 0 to 9 
'  minus sign and decimal point.
'================================

# Include "window9.bi"
#include "string.bi"
#include "crt.bi"

Dim shared As integer event
DIM shared AS MSG msg
DIM shared AS STRING sTxt  ', oldsTxt
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
      '                                                                                
      if wParam=47 then wp2=0         ' / not allowed
      if wParam=46 and Instr(txt, ".") then wp2=0   ' one dot only
      if wParam=45 and txtpos then wp2=0      ' - only in pos 0
      if wParam<>VK_BACK then         ' wParam <> Backspace
         if wParam<45 or wParam>57 then wp2=0
      endif
   endif
  endif
  CallWindowProc(PrevWinProc, hWnd, uMsg, wp2, lParam)
  if uMsg=WM_CHAR then
         sTxt = GetGadgetText(3)
         numb = val(sTxt)
         sTxt = format(numb, "####0.000")
         SetGadgetText(4,sTxt)
  endif
End Sub


' Create window and contained gadgets
var main = OpenWindow ("Numeric Input ", 300,10,300,300)
 
var txt1 = TextGadget(1,10,15,100,30,"Input Number:")
TextGadget(2, 10, 60, 100,30, "Formatted Number")

' Set up First StringGadget
var st1 = StringGadget (3,120,10,120,25, "", ES_RIGHT or WS_BORDER)
SetGadgetFont (3, CINT(LoadFont ("arial", 12))) 'Font Gadget

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

' Set up Second StringGadget
var st2 = StringGadget (4,120,55,120,25, "", ES_RIGHT or ES_READONLY or WS_BORDER)
SetGadgetFont (4, CINT(LoadFont ("arial", 12))) 'Font Gadget

SetFocus(st1) 


Do
 Var ev=WindowEvent
 If ev=EventClose Then End
Loop
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBoxLothar

Post by jj2007 »

RNBW wrote:The following is an example of filtered numeric entry into a StringGadget (textbox) using subclassing and FBGUI Library for Windows
Glad to see you start liking the subclassing technique ;-)
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBoxLothar

Post by RNBW »

jj2007 wrote:
RNBW wrote:The following is an example of filtered numeric entry into a StringGadget (textbox) using subclassing and FBGUI Library for Windows
Glad to see you start liking the subclassing technique ;-)
I think it is probably stretching it a bit to say that I like the subclassing technique, because I still don't fully understand it and what I would like to do is to format it to a specific number of decimal points in the Input StringGadget, rather than the Output StringGadget and I've not worked out how to do that yet. But, just to give you a bit of my background, I was a Construction Project Manager for about 40 years and what I found out very early was that there had to be an acceptable solution to a problem. It might not be the one you would prefer to use, but having taken into account the associated risks and costs, if it works use it.

I will try to get a better understanding, but I know it does the job and so I will use it, unless I find something better. So at the moment, in my book you are at the top of the tree!
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Numeric Entry in an EditBoxLothar

Post by jj2007 »

RNBW wrote:I will try to get a better understanding
Have a look at the new subclassing thread.
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

I have posted an example of numeric entry in a grid of textboxes using Lothar Schirm's Simple Windows API Library here viewtopic.php?f=8&t=24617&start=45, which followers of this thread may have an interest.
RNBW
Posts: 267
Joined: Apr 11, 2015 11:06
Location: UK

Re: Numeric Entry in an EditBox

Post by RNBW »

It's some time since I visited this subject. I've just purchased a Windows tablet and was copying some programs to it. Something clicked and I realised how to achieve what I wanted without sub-editing and also to very simply restrict the number of characters into e Editbox.

Code: Select all

'=============================================
'  NUMERIC INPUT IN AN EDITBOX
'  File Name: NumericEntryIntoAnEditbox_WinGUI_2.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.
'  It also ensures that if .123 is entered it displays 0.123 and if
'  -.123 is entered -0.123 is displayed.
'  It also allows the programmer to restrict the number of characters
'  to be entered (including "-" and "."
'  Code by RNBW. 
'============================================

#Include "WinGUI.bi"

Dim As HWND Window_Main, Button_Ok, Edit_1
Dim As MSG msg
dim As String txt, oldtxt
Dim As Integer pos0   


Function num(ByVal txt As String) As String
	'Function to check that character input is 0-9, - or .
	'The number of characters that can be entered will depend
	'on the width of the Editbox and the size of the font.
	'The Programmer is to check this and enter the maximum number
	'of characters in the variable numChars
	
	Dim As String num1
	Dim As Integer i, a, t, maxNumChars
	
' enter the maximum number of characters to be entered and displayed
' in the Editbox.
' This will be dependent on the size of the Editbox and the size of font.
' The programmer will have to calculate this.  I do it by simply typing in
' characters in the Editbox and counting them when it is full and not
' scrolling horizontally	
	maxNumChars	= 12	
	For i = 1 To maxNumChars	
		a = Asc(Mid(txt,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 num1 = "0" + num1
		If a = 45 Or a = 46 or a > 47 and a < 58 then num1 = num1 + Chr(a)
	Next
	
	a=asc(mid(txt,1,1))
	if a = 45 and mid(txt,2,1) = "." then num1 = "-0" + num1
	
	Return num1
	
End Function


'Create a window with an Editbox:
Window_Main = Window_New   (100, 100, 400, 150, "Numeric Entry Filter!")
Var Label_txt = Label_New  (10, 10, 150, 20, "Enter numbers:",, Window_Main)
Edit_1 = EditBox_New       (150, 10, 100, 20, "", ES_RIGHT, Window_Main)

'Set timer to 300 miliseconds: increasingit is not eligible. this value shows the character entered 
'and then removed if it is not eligible.
SetTimer(Window_Main, 0, 300, 0 )

Do
	WaitEvent(Window_Main,msg)
	Select Case msg.message
		Case WM_TIMER
			'Check contents of the edit box every 300 millisecinds
			txt = EditBox_GetText(Edit_1)   'get text from edit box
			oldtxt = txt      'make text the oldtext
			txt = num(txt)  'gets new text from function num(txt) which does the checking
			If oldtxt <> txt Then
				EditBox_SetText(Edit_1, txt)   'if old text is not the same as the new text then use new text
				pos0 = Len(txt)   'position of character is the length of the current text
				SendMessage(Edit_1, EM_SETSEL, pos0, pos0)
			End If
		Case WM_LBUTTONDOWN
			If msg.hwnd = Button_Ok Then Print EditBox_GetText(Edit_1)  'print text to console
	End Select
Loop Until Window_Event_Close(Window_Main, msg)

End
I hope someone finds it useful.
Post Reply