Page 1 of 2
Numeric Entry into a EditBox
Posted: Wed Jul 11, 2018 3:43 pm
by RNBW
I have been trawling through the forum for examples of numeric input into a textbox. What I wanted was the following:
Check each character as it is entered to ensure that:
• The character was limited to 0 to 9, minus and decimal point (period)
• Minus can only occur as the first character entered
• There can only be one occurrence of minus
• There can only be one occurrence of a decimal point
• If the first character entered is a decimal point (.123) it will be displayed as 0.123
• If the first character is minus and the second a decimal point (-.123) it will be displayed as -0.123
• The display will be right justified
• It must be editable
I couldn’t find code that did all of these, but was able to find two that came close. I have amalgamated the two. Credit is given in the code to the writers of the original code. I am very grateful to them and I hope that the code below will be useful. I shall be grateful if anyone can improve it or put me right if I have got anything wrong.
Code: Select all
;--------------------------------------------------------------------------------------------
; Numeric input
;---------------------------------------------------------------------------------------------
; This is an amalgamation of two programs. One from Danilo
; included in RSBasic's WinAPI Library (StringGadget section)
; and BasicallyPure's program in the Purebasic forum
; (https://www.purebasic.fr/english/viewtopic.php?f=13&t=50565&hilit=Numeric+entry&start=0)
; It accepts characters 0 to 9 minus and period.
; It accepts a minus only as the first character.
; It only accepts one minus sign and one period in the entry.
; An entry of .123 displays as 0.123
; An entry of -.123 is displayed as -0.123
; The amalgamation of code has been produced by RNBW, who is grateful
; to all the contributors to the code:
; Danilo
; BasicallyPure
; asked for by 'akee'
; inspired by 'IdeasVacuum'
; key assist from 'Shardik'
;---------------------------------------------------------------------------------------------
EnableExplicit
Procedure.s CheckNumeric(iStrGadget.i)
;purpose: limit StringGadget to accept only numeric input
;with support for floating poing characters: . - + E e
Protected.i iCount, iTextLength, iAccept, iDecimal, iExp, iNeg
Protected.s sNewText, sChar, sGadgetText
sGadgetText = GetGadgetText(iStrGadget)
iTextLength = Len(sGadgetText)
For iCount = 1 To iTextLength
sChar = Mid(sGadgetText, iCount, 1)
iAccept = #False
Select Asc(sChar)
Case 48 To 57 ; Accepted numbers
iAccept = #True
If iExp = 1 : iExp + 1 : EndIf
Case 43, 45 ; Minus or Plus sign
If iCount = 1
iAccept = #True : iNeg = 1
ElseIf iExp = 1
iAccept = #True : iExp + 1
EndIf
Case 46 ; period
If Not iDecimal And Not iExp
iDecimal = #True : iAccept = #True
If iCount - iNeg = 1 : sChar = "0" + sChar : EndIf
EndIf
Case 69, 101 ; 'e' or 'E'
If Not iExp And iCount > 1 + iNeg
iExp = 1 : iAccept = #True
EndIf
EndSelect
If iAccept : sNewText + sChar : EndIf
Next
SetGadgetText(iStrGadget, sNewText)
iTextLength = Len(sNewText)
;windows only
SendMessage_(GadgetID(iStrGadget),#EM_SETSEL,iTextLength,iTextLength) ;Set cursor to end of string
EndProcedure
If OpenWindow(0,0,0,300,150,"Number of Decimal Places",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
StringGadget(1,10,10,200,20,"",#PB_Text_Right)
LoadFont (1, "Monaco", 11, #PB_Font_Bold)
SetGadgetFont(1, FontID(1))
Repeat
Define EventID=WaitWindowEvent()
If EventID=#PB_Event_Gadget
Select EventGadget()
Case 1
If EventType() = #PB_EventType_Change
CheckNumeric(EventGadget())
EndIf
EndSelect
EndIf
If EventID = #PB_Event_CloseWindow
End
EndIf
ForEver
EndIf
Re: Numeric Entry into a EditBox
Posted: Thu Jul 12, 2018 7:35 am
by idle
seems to work well, but not "e" exp, needs a bit more thought
as you can type 123.456e1234
the exponent needs to be limited in the range, for float +/- 38 or double +/- 308
so if you have "1." entered you can flag it as a potential of exp and if "e" is entered then range check the numbers after to be
within +/- 38 for float or +/- 308 for double
not sure how to do that right now but will look at it in the morning
Re: Numeric Entry into a EditBox
Posted: Fri Jul 13, 2018 11:39 am
by RNBW
idle wrote:seems to work well, but not "e" exp, needs a bit more thought
as you can type 123.456e1234
the exponent needs to be limited in the range, for float +/- 38 or double +/- 308
so if you have "1." entered you can flag it as a potential of exp and if "e" is entered then range check the numbers after to be
within +/- 38 for float or +/- 308 for double
not sure how to do that right now but will look at it in the morning
You are right that the incorporation of the entry of numbers such as 123.456e1234 (or more importantly 123.456e-1234) needs more thought. With what I had in mind, I wouldn't require such numbers to actually be entered.
One of the problems is that the code as written only allows for a minus sign to be the first character entered and only one minus sign is permitted. The e (or E) shouldn't be too much of a problem to change, but you couldn't enter 123e-12 or -123e-12, the first because of the rule I've just mentioned and the latter with a double no-no because it has a minus in the middle of the entry and also two minus signs.
These problems have to be overcome and it's not easy. I must say, if I was going to need to enter a 123e-12 type number, I would probably use a completely different method, such as entering the whole number and then carrying out a check on its validity, or alternatively enter a number without the e-12 part and identify that with a label after the textbox and deal with the number itself in code outside the entry. Personnally, I would favour the latter method. It's much easier to deal with.
I currently don't have time to look into it, but if anyone could come up with solutions I would like to see them.
Personnally, my next step is to produce a grid of textboxes with numeric entry into them. If anyone has any ideas, it would save my poor old brain a few headaches!
Re: Numeric Entry into a EditBox
Posted: Fri Jul 13, 2018 1:30 pm
by captain_skank
RNBW wrote:idle wrote:
Personnally, my next step is to produce a grid of textboxes with numeric entry into them. If anyone has any ideas, it would save my poor old brain a few headaches!
I use a scroll areagadget and an list (array) of stringgadgets for my entrirley PB based grid gadget - but it's a bit of a bodge
Re: Numeric Entry into a EditBox
Posted: Fri Jul 13, 2018 2:19 pm
by RNBW
I must be going daft (ask my wife she'll probably confirm that - she's being saying it for years). The code DOES allow the input of numbers such as 123e24 and -123e-24. I found I was checking it out using old code, which didn't allow it because I had stripped out the incorporation of 'e'. I decided to include it before I posted the code.
Re: Numeric Entry into a EditBox
Posted: Fri Jul 13, 2018 5:09 pm
by RNBW
captain_skank wrote:RNBW wrote:idle wrote:
Personnally, my next step is to produce a grid of textboxes with numeric entry into them. If anyone has any ideas, it would save my poor old brain a few headaches!
I use a scroll areagadget and an list (array) of stringgadgets for my entrirley PB based grid gadget - but it's a bit of a bodge
Is your grid gadget on the forum?
Re: Numeric Entry into a EditBox
Posted: Thu Jul 19, 2018 9:31 am
by RNBW
Code: Select all
;windows only
SendMessage_(GadgetID(iStrGadget),#EM_SETSEL,iTextLength,iTextLength) ;Set cursor to end of string
Is there an equivalent Mac OS equivalent to #EM_SETSEL, or is there another way of achieving the same result?
Re: Numeric Entry into a EditBox
Posted: Sat Aug 11, 2018 3:39 pm
by RNBW
Unfortunately, the code does not work if you try to edit the entered number if a single character precedes the decimal point, such as 1.234 or 0.234
I've tried to resolve this, but unsuccessfully. Can anyone help?
Re: Numeric Entry into a EditBox
Posted: Sat Aug 11, 2018 4:03 pm
by Shardik
RNBW wrote:Code: Select all
;windows only
SendMessage_(GadgetID(iStrGadget),#EM_SETSEL,iTextLength,iTextLength) ;Set cursor to end of string
Is there an equivalent Mac OS equivalent to #EM_SETSEL, or is there another way of achieving the same result?
You may take a look into this
cross-platform example which allows to get and set the cursor position in a StringGadget. To position the cursor at the end you should change
Code: Select all
SetCursorPosition(0, 16) ; Set cursor in front of 'fox'
to
Code: Select all
SetCursorPosition(0, Len(GetGadgetText(0)))
Re: Numeric Entry into a EditBox
Posted: Sun Aug 12, 2018 1:52 am
by Dude
RNBW wrote:The character was limited to 0 to 9, minus and decimal point (period)
You can't hard-check for a decimal point (period) as different countries use different decimal separators - some use a comma, for example. So you need to get the locale setting for the decimal separator at runtime, and check for that in your text input routine (
not for a period).
Re: Numeric Entry into a EditBox
Posted: Mon Aug 13, 2018 11:42 am
by RNBW
Dude wrote:RNBW wrote:The character was limited to 0 to 9, minus and decimal point (period)
You can't hard-check for a decimal point (period) as different countries use different decimal separators - some use a comma, for example. So you need to get the locale setting for the decimal separator at runtime, and check for that in your text input routine (
not for a period).
What I have in mind to ultimately use the code for will be British only, so a check for a decimal point is OK. However, I do take your point that for a universal solution a check should also be made for a comma. I should say, though, that this can lead to all sorts of formatting arguments and solutions (how thousands are divided and so on), so the code will be quite long and complex and, I would suggest, not for the simple numeric entry into an EditBox that I am looking at.
Some of the separation of thousands 1,234,567 1 234 567 1'234'567 and that's not taking into account how the decimal point is dealt with.
Of course, there are also the arguments about the types of numbers that should be entered, and there are many of these. Maybe I should have headed the thread "Simple Numeric Entry into an EditBox".
Re: Numeric Entry into a EditBox
Posted: Mon Aug 13, 2018 11:46 am
by RNBW
Shardik wrote:
You may take a look into this
cross-platform example which allows to get and set the cursor position in a StringGadget. To position the cursor at the end you should change
Code: Select all
SetCursorPosition(0, 16) ; Set cursor in front of 'fox'
to
Code: Select all
SetCursorPosition(0, Len(GetGadgetText(0)))
Thank you. I'll have a look at the code.
Re: Numeric Entry into a EditBox
Posted: Mon Aug 27, 2018 5:03 pm
by RNBW
RNBW wrote:Unfortunately, the code does not work if you try to edit the entered number if a single character precedes the decimal point, such as 1.234 or 0.234
I've tried to resolve this, but unsuccessfully. Can anyone help?
The only way that I can see to get over this is to remove or REM the line
Code: Select all
If iCount - iNeg = 1 : sChar = "0" + sChar : EndIf
The user can then enter 0.123 -0.123 .123 or -.123 depending on preference. It is then possible to format the number after input. I'll have a look at this.
Shardick
I must say I like the solution you gave for setting the cursor position. Your page
is very useful.
Re: Numeric Entry into a EditBox
Posted: Mon Oct 22, 2018 11:26 am
by RNBW
Time flies. I meant to look at this straight away after my last post.
At the moment, there are two problems that I have with the code that I originally posted.
1. Whenever you edit the number, the cursor then flies to after the last digit, and
2. If you try to edit a single number before the decimal point, it can only be done by entering a character before the first character and then deleting the character after the inserted character.
I suspect that (2) might be resolved by a solution to (1).
Does anyone know how you can insert a character and the cursor remain at the inserted character, rather than flying to after the last digit?
Re: Numeric Entry into a EditBox
Posted: Wed Oct 24, 2018 11:01 am
by RNBW
RNBW wrote:Time flies. I meant to look at this straight away after my last post.
At the moment, there are two problems that I have with the code that I originally posted.
1. Whenever you edit the number, the cursor then flies to after the last digit, and
2. If you try to edit a single number before the decimal point, it can only be done by entering a character before the first character and then deleting the character after the inserted character.
I suspect that (2) might be resolved by a solution to (1).
Does anyone know how you can insert a character and the cursor remain at the inserted character, rather than flying to after the last digit?
Well 75 views at my last post, but no suggestions how to get over the problem. I was hoping that someone would come up with perhaps a sub-classing solution (which has been done on other forums). I have to admit not being able to fully get my head around sub-classing. I have tried but unsuccessfully.
So not to be detered, I looked for a completely different solution. I had previously scoured the Purebasic forums (English and German) and looked back at some of the solutions I found. I came up with the code below, which I modified a bit. It gives me what I want in respect of editing, i.e. leaving the cursor at the point of edit rather than jumping to the end each time. I would be pleased to see any suggestions for improvements.
Code: Select all
;-------------------------------------------------------------------------
; Filename: NumericInput_04.pb
;
; From original code by Danilo and ts-soft
; http://www.purebasic.fr/german/viewtopic.php?p=299222#p299222
;
; Modifications by RNBW 22 October 2018
;
; Input numeric values in the range "-", ".", "0 to 9"
; into a StringGadget
; The number is entered into the first box and this is then
; displayed in the second box as a number formatted to
; 3 decimal places. The number of decimal places can be
; changed by changing the value of dec in the program.
; If you want thousand commas in the displayed number,
; comment out "formNum = StrD(numb, dec)" and
; remove the comment to
; "formNum = FormatNumber(numb,dec)"
;-------------------------------------------------------------------------
EnableExplicit
Global formNum.s
Global numb.d
Global dec.i
Procedure checkFloatInput(gadget)
Protected start.i, count.i, pointcount.i, new.s
SendMessage_(GadgetID(gadget), #EM_GETSEL, @start, 0)
Protected txt$ = GetGadgetText(gadget)
Protected *p.Character = @txt$
While *p\c ; <> 0
If *p\c = '.'
pointcount + 1
If pointcount < 2
new + Chr(*p\c)
Else
If start > count : start - 1 : EndIf
EndIf
ElseIf count = 0 And *p\c = '-'
new + Chr('-')
ElseIf *p\c >= '0' And *p\c <= '9'
new + Chr(*p\c)
Else
start - 1
EndIf
*p + SizeOf(Character)
count + 1
Wend
SetGadgetText(gadget, new)
SendMessage_(GadgetID(gadget), #EM_SETSEL, start, start)
EndProcedure
Define event
If OpenWindow(0, 0, 0, 300, 150, "Numeric Input Into A StringGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If LoadFont(1, "Arial", 10)
SetGadgetFont(#PB_Default, FontID(1)) ; Set the loaded Arial 10 font as new standard
EndIf
TextGadget(0, 10, 20, 200, 20, "Enter Number in box below")
TextGadget(3, 10, 85, 200, 20, "Display formatted number")
If LoadFont(2,"Arial",11, #PB_Font_Bold)
SetGadgetFont(#PB_Default, FontID(2)) ; Set the loaded Arial 15 font as new standard
EndIf
StringGadget(1, 10, 50, 100, 25, "", #ES_RIGHT)
StringGadget(2, 10, 110, 100, 25, "", #ES_RIGHT | #ES_READONLY) ; this gadget is read-only
SetActiveGadget(1) ; set focus in StringGadget(1)
Repeat
event = WaitWindowEvent()
If event = #PB_Event_CloseWindow : End
ElseIf event = #PB_Event_Gadget
;If EventGadget() = 1 Or EventGadget() = 2 ; this line is not actually required
If EventType() = #PB_EventType_Change
checkFloatInput(EventGadget())
numb = ValD(GetGadgetText(1))
dec = 3 ; set number of decimal places
formNum = StrD(numb, dec)
;formNum = FormatNumber(numb,dec) ; this would place commas in the displayed number
SetGadgetText(2, formNum)
EndIf
;EndIf
EndIf
ForEver
EndIf